# Troubleshooting

## Common Issues

### "fork failed: Device not configured" / "posix_spawnp failed" (macOS)
Symptom: after the server has been running for a long time, opening a new terminal fails with `Failed to create tmux session: posix_spawnp failed`.

Forge ≥ 0.5.46 auto-recovers by killing idle sessions on PTY exhaustion (both random-name and fixed-name `create` paths go through the same recovery). On older versions, or if the macOS PTY pool is genuinely too small, raise the limit:
```bash
sudo sysctl kern.tty.ptmx_max=2048
echo 'kern.tty.ptmx_max=2048' | sudo tee -a /etc/sysctl.conf
```
Manual cleanup if needed:
```bash
tmux list-sessions
tmux kill-session -t <name>      # kill specific
tmux kill-server                  # nuclear option — kills ALL tmux sessions
```

### Session cookie invalid after restart
Fix AUTH_SECRET so it persists:
```bash
echo "AUTH_SECRET=$(openssl rand -hex 32)" >> ~/.forge/data/.env.local
```

### Pipeline push asks for OTP / "2fa_verify" / "Keystroke mode is macOS-only"
Pipeline `git push` should never hit an SSH 2FA wall when the GitLab
connector has a PAT: Forge rewrites SSH-style remotes
(`git@host:owner/repo.git`) to HTTPS+PAT per task process (needs git ≥ 2.31).
If you still see a 2FA abort:
- Check Settings → Connectors → GitLab has a valid token.
- If your GitLab's SSH hostname differs from the HTTPS `base_url` host, add
  it to the connector's `ssh_aliases`.
- An old wizard may still carry a "GitLab SSH 2FA" post-login step — resync
  the enterprise marketplace to pull the updated wizard; the warning row
  disappears from the Enterprise badge.

### Orphan processes after Ctrl+C
Use `forge server stop` or:
```bash
pkill -f 'telegram-standalone|terminal-standalone|next-server|cloudflared'
```

### Tunnel stuck at "starting"
```bash
pkill -f cloudflared
# Then restart tunnel from UI or Telegram
```

### Forgot admin password
```bash
forge --reset-password
```

### Terminal tabs lost after restart
Terminal state is saved in `~/.forge/data/terminal-state.json`. If corrupted:
```bash
rm ~/.forge/data/terminal-state.json
# Restart server — tabs will be empty but tmux sessions survive
```

### Terminal input is laggy
Usually caused by high system load. Check:
- System memory — if heavily swapping, kill some processes
- Clean up old tmux sessions: `tmux list-sessions` then `tmux kill-session -t <name>`
- Reduce polling: open tabs are limited to 20 by LRU eviction
- Workspace terminals auto-reconnect on disconnect; no need to manually reopen

### "Connection error" in workspace terminal
The WebSocket dropped (system suspend, network blip). Forge auto-reconnects after 2s and re-attaches to the same tmux session. If it keeps happening:
- Check `~/.forge/data/forge.log` for terminal-standalone errors
- Restart: `forge server restart`

### gh CLI not authenticated (Issue Scanner)
```bash
gh auth login
```

### Skills not syncing
Click "Sync" in Skills tab. Check `skillsRepoUrl` in Settings points to valid registry.

### Multiple instances conflict
Use different ports and data directories:
```bash
forge server start --port 4000 --dir ~/.forge/data_demo
forge server stop --port 4000 --dir ~/.forge/data_demo
```

### Page shows "Failed to load chunk"
Clear build cache:
```bash
rm -rf .next
pnpm build  # or forge server rebuild
```

### npm install fails with ENOTEMPTY
Previous install was interrupted. Clean up and retry:
```bash
rm -rf $(npm root -g)/@aion0/forge $(npm root -g)/@aion0/.forge-*
npm install -g @aion0/forge
```

### Chat keeps looping / "thinking…" never finishes
The agent got stuck retrying a tool that can't succeed (e.g. a truncated
result it keeps re-fetching). While a turn is running the `/chat` composer
stays usable:
- **■ Stop** — aborts the tool-call loop at the next step and posts a
  "⏹ Stopped by user" message. Use this to break a runaway turn.
- **Send** — type a correction/extra instruction and send it; while a turn
  is running it's spliced into THAT turn (the agent reads it on its next
  step), so you can redirect without cancelling. A normal `POST /messages`
  is deliberately NOT used here — it would spawn a second concurrent loop on
  the same session.

These hit `POST /api/sessions/:id/abort` and `/note` on the chat backend, so
any client (web `/chat`, extension) can drive them. `/note` no-ops (409) when
no turn is running — the page then sends it as a normal new message instead.

## Logs

- Background server: `~/.forge/data/forge.log`
- Dev mode: terminal output
- View with: `tail -f ~/.forge/data/forge.log`

## Reset Everything

```bash
# Stop server
forge server stop

# Reset password
forge --reset-password

# Clear all data (nuclear option)
rm -rf ~/.forge/data
# Restart — will create fresh data directory
```
