[BUG] Config file corruption with "JSON Parse error: Unterminated string" in Docker container

Resolved 💬 3 comments Opened Jan 29, 2026 by cbarraford Closed Feb 2, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Summary

Claude Code's configuration file (~/.claude.json) is becoming corrupted in the Docker container with "JSON Parse
error: Unterminated string". This causes Claude CLI to hang waiting for interactive input, which cannot be
provided in automated/containerized environments. I am running v2.1.20

Additionally, even though I'm running claude in headless mode, i still get prompted to handle a "configruation error" which halts my code.

## Error Output

[2026-01-29 15:32:32] [WARNING] Claude config file at /home/huginn/.claude.json is corrupted: Unterminated string starting at: line 180 column 3 (char 5745) - deleting
[2026-01-29 15:32:32] [INFO] Claude output streaming: enabled
[2026-01-29 15:32:32] [INFO] [CLAUDE] Starting Claude Code session (streaming enabled)
[CLAUDE] Claude configuration file at /home/huginn/.claude.json is corrupted: JSON Parse error: Unterminated
string
[CLAUDE] The corrupted file has already been backed up.
[CLAUDE] A backup file exists at: /home/huginn/.claude.json.backup.1769553810124
[CLAUDE] You can manually restore it by running: cp "/home/huginn/.claude.json.backup.1769553810124"
"/home/huginn/.claude.json"
[CLAUDE]
[CLAUDE] ╭────────────────────────────────────────────────────────────────────╮
[CLAUDE] │ │
[CLAUDE] │ Configuration Error │
[CLAUDE] │ │
[CLAUDE] │ The configuration file at /home/huginn/.claude.json contains │
[CLAUDE] │ invalid JSON. │
[CLAUDE] │ │
[CLAUDE] │ JSON Parse error: Unterminated string │
[CLAUDE] │ │
[CLAUDE] │ Choose an option: │
[CLAUDE] │ ❯ 1. Exit and fix manually │
[CLAUDE] │ 2. Reset with default configuration │
[CLAUDE] │ │
[CLAUDE] ╰────────────────────────────────────────────────────────────────────╯

## Environment Details

Docker Setup:

  • Running Claude Code in Docker container as non-root user huginn
  • Config file mounted as: ~/.claude.json:/home/huginn/.claude.json (read-write)
  • Session directory mounted as: ~/.claude:/home/huginn/.claude (read-write)

Here are my volumes in my docker-compose.yml file.

    volumes:
      # Persistent state for CI fix tracking and logs
      - ./state:/app/state
      # Docker socket for docker/docker compose commands
      - /var/run/docker.sock:/var/run/docker.sock
      # Claude session data (needs write access for session files)
      - ~/.claude:/home/huginn/.claude
      # Claude config (needs write access)
      - ~/.claude.json:/home/huginn/.claude.json

Current Mitigation (Partial):
We've implemented validation and retry logic in huginn/claude_runner.py:

  • _ensure_valid_claude_config() validates JSON before each Claude invocation
  • _is_config_error_prompt() detects the interactive error prompt
  • Automatic retry with config reset on corruption detection
  • See: [claude_runner.py:350-575](huginn/claude_runner.py:350)

However, this doesn't prevent the corruption from occurring initially.

## Root Cause Hypothesis

The "Unterminated string" JSON error suggests the file is being written incompletely. Possible causes:

  1. Race condition during concurrent writes: Claude CLI may be writing to config while another process reads it
  2. Process crash during write: If Claude CLI crashes mid-write, the JSON becomes malformed
  3. File locking issues: The mounted volume might not properly handle file locking between host and container
  4. Buffer flushing: Incomplete buffer flush during file write operations

## Impact

  • Severity: High - Blocks automated workflow execution
  • Frequency: Intermittent but recurring
  • Recovery: Requires manual intervention or automated detection and reset (currently implemented as

workaround)

## Expected Behavior

Claude CLI should:

  1. Use atomic writes when updating ~/.claude.json (write to temp file, then atomic rename)
  2. Implement proper file locking to prevent concurrent write corruption
  3. In non-interactive environments (no TTY), automatically reset corrupted config instead of prompting
  4. Validate JSON before persisting to disk

## Requested Fix

### Option 1: Atomic File Writes (Preferred)
Implement atomic writes for config updates:
```python
# Write to temporary file first
tmp_file = config_path.with_suffix('.json.tmp')
with tmp_file.open('w') as f:
json.dump(config_data, f)
f.flush()
os.fsync(f.fileno()) # Ensure data reaches disk

# Atomic rename (POSIX guarantees atomicity)
tmp_file.rename(config_path)

Option 2: File Locking

Use advisory file locking to prevent concurrent writes:
import fcntl

with config_path.open('r+') as f:
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
try:
config_data = json.load(f)
# ... modify config ...
f.seek(0)
f.truncate()
json.dump(config_data, f)
f.flush()
os.fsync(f.fileno())
finally:
fcntl.flock(f.fileno(), fcntl.LOCK_UN)

Option 3: Non-Interactive Auto-Recovery

When running without a TTY and config is corrupted, automatically reset to default instead of prompting:
if (!process.stdout.isTTY && configIsCorrupted) {
console.error('Config corrupted in non-interactive mode - auto-resetting');
resetToDefaultConfig();
// Continue execution instead of exiting
}

Reproduction

While intermittent, corruption seems more likely when:

  1. Multiple Claude CLI processes run concurrently (though we use git worktrees to isolate)
  2. Container is stopped abruptly during Claude execution
  3. High-frequency Claude CLI invocations in loop mode

Workaround

Current mitigation in our code:

  1. Pre-validate config JSON before each Claude invocation
  2. Detect interactive config error prompt in Claude output
  3. Auto-delete corrupted config and retry once
  4. Exit with error if corruption persists after reset

See implementation: huginn/claude_runner.py:350-575

Additional Context

  • Related to file I/O in containerized environments with mounted volumes
  • May be Docker-specific (file system semantics differ from native)
  • Config file structure suggests it's written frequently (possibly on every CLI invocation)

---
Labels: bug, claude-cli, config-corruption, docker
Priority: High
Component: Claude Code CLI
Version: Latest (as of 2026-01-29)
```

What Should Happen?

claude should be able to run in a docker container, mounting claude auth files so i can use my claude max plan without corrupting config files

Error Messages/Logs

[CLAUDE] Claude configuration file at /home/huginn/.claude.json is corrupted: JSON Parse error: Unterminated
  string
  [CLAUDE] The corrupted file has already been backed up.
  [CLAUDE] A backup file exists at: /home/huginn/.claude.json.backup.1769553810124
  [CLAUDE] You can manually restore it by running: cp "/home/huginn/.claude.json.backup.1769553810124"
  "/home/huginn/.claude.json"
  [CLAUDE]
  [CLAUDE] ╭────────────────────────────────────────────────────────────────────╮
  [CLAUDE] │                                                                    │
  [CLAUDE] │ Configuration Error                                                │
  [CLAUDE] │                                                                    │
  [CLAUDE] │ The configuration file at /home/huginn/.claude.json contains       │
  [CLAUDE] │ invalid JSON.                                                      │
  [CLAUDE] │                                                                    │
  [CLAUDE] │ JSON Parse error: Unterminated string                              │
  [CLAUDE] │                                                                    │
  [CLAUDE] │ Choose an option:                                                  │
  [CLAUDE] │ ❯ 1. Exit and fix manually                                         │
  [CLAUDE] │   2. Reset with default configuration                              │
  [CLAUDE] │                                                                    │
  [CLAUDE] ╰────────────────────────────────────────────────────────────────────╯

Steps to Reproduce

Steps to Reproduce

Note: This bug is intermittent and may require multiple attempts to reproduce. The following steps increase
the likelihood of triggering the corruption.

### Prerequisites

  1. Docker installed and running
  2. Claude Code CLI authentication token configured
  3. A project with the Huginn setup (or any project that runs Claude CLI in Docker repeatedly)

### Method 1: High-Frequency Execution (Most Reliable)

```bash
# 1. Set up Docker container with mounted Claude config
docker-compose.yml:
volumes:

  • ~/.claude:/home/huginn/.claude
  • ~/.claude.json:/home/huginn/.claude.json

# 2. Run Claude CLI repeatedly in loop mode
make run-loop LOOP_INTERVAL=1

# 3. While running, in another terminal, repeatedly read the config
while true; do
cat ~/.claude.json > /dev/null
sleep 0.1
done

# 4. Let this run for 30-60 minutes
# Corruption typically occurs within this timeframe

Method 2: Simulated Crash During Write

# 1. Start a long-running Claude CLI task in Docker
docker compose run --rm huginn --loop 45

# 2. While Claude is actively executing (watch logs for "[CLAUDE]" output):
docker compose kill -s SIGKILL huginn

# 3. Inspect the config file
cat ~/.claude.json
# If corrupted, you'll see incomplete JSON

# 4. Try to run Claude again
docker compose run --rm huginn
# Should show the corruption error prompt

Method 3: Concurrent Docker Instances

# 1. Launch multiple Claude CLI instances simultaneously
# Each sharing the same mounted config file
for i in {1..5}; do
docker compose run --rm huginn --dry-run &
done

# 2. Wait for all to complete
wait

# 3. Check config file integrity
python3 -c "import json; json.load(open('/home/user/.claude.json'))"
# If corrupted, will show JSON decode error

Method 4: Storage I/O Pressure

# 1. Create I/O pressure on the host system
dd if=/dev/zero of=/tmp/io-load bs=1M count=1000 &
sync

# 2. Run Claude CLI in loop mode
docker compose run --rm huginn --loop 1

# 3. Monitor for corruption
while true; do
if ! python3 -c "import json; json.load(open('/home/user/.claude.json'))" 2>/dev/null; then
echo "CORRUPTION DETECTED!"
cat ~/.claude.json
break
fi
sleep 5
done

Verification of Corruption

When successfully reproduced, you should see:

# 1. Invalid JSON in the config file
cat ~/.claude.json
# Output shows unterminated string, like:
# {"key": "value", "another": "incomplet

# 2. Claude CLI shows interactive error prompt
docker compose run --rm huginn
# Output shows the "Configuration Error" dialog box

# 3. Backup file exists
ls -la ~/.claude.json.backup.*
# Shows timestamped backup files

Expected vs Actual Behavior

Expected:

  • ~/.claude.json should always contain valid JSON
  • Claude CLI should handle write failures gracefully
  • No interactive prompts in non-interactive environments

Actual:

  • ~/.claude.json becomes corrupted with unterminated strings
  • Claude CLI shows interactive prompt requiring user input
  • Process hangs waiting for input that cannot be provided in containerized environments

System Information

# Collect this information when filing the bug report
docker --version
uname -a
df -h ~/.claude.json # Check filesystem type
mount | grep "\.claude" # Check mount options

Debug Information to Collect

If you successfully reproduce the issue:

# 1. Save the corrupted file
cp ~/.claude.json ~/claude-corrupted-$(date +%s).json

# 2. Check file size and last modification time
ls -la ~/.claude.json

# 3. Check for partial writes (file size changes)
watch -n 0.1 'ls -la ~/.claude.json'

# 4. Check Docker logs for any errors
docker compose logs huginn | grep -i error

# 5. Examine backup files
ls -la ~/.claude.json.backup*
cat ~/.claude.json.backup.* | head -20

Factors That Increase Likelihood

  • ✅ Running in Docker container with volume mounts
  • ✅ High-frequency Claude CLI invocations (< 5 minute intervals)
  • ✅ Abrupt container termination (SIGKILL, host reboot)
  • ✅ Multiple concurrent Claude CLI instances
  • ✅ Network file systems (NFS, CIFS) for Docker volumes
  • ✅ Running on systems with high I/O load

Notes

  • Corruption is intermittent - may take multiple attempts
  • Most common error: "JSON Parse error: Unterminated string"
  • Less common: "Unexpected token" or "Unexpected end of JSON input"
  • Backup files (.claude.json.backup.*) may also be corrupted if crash occurs during backup operation

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.20 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

_No response_

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗