Background agents fail on Termux - hardcoded /tmp path

Status Closed — not planned
Reported on v2.0.76
Maintainer reply None cached
Activity 12 comments · opened Dec 29, 2025 · closed Mar 2, 2026

Bug Description

Claude Code uses hardcoded /tmp/claude for background task directories. On Termux/Android, /tmp is not accessible (permission denied).

Error

EACCES: permission denied, mkdir '/tmp/claude/-data-data-com-termux-files-home/tasks'

Expected Behavior

Should use os.tmpdir() (returns /data/data/com.termux/files/usr/tmp on Termux) or respect TMPDIR environment variable.

Environment

  • Platform: Android/Termux (linux arm64)
  • Claude Code version: 2.0.76
  • Node.js os.tmpdir() returns: /data/data/com.termux/files/usr/tmp

Reproduction

  1. Install Claude Code on Termux
  2. Try to spawn background agents using Task tool with run_in_background: true
  3. Error occurs

Workaround

Using proot wrapper to bind mount tmp:

proot -b /data/data/com.termux/files/usr/tmp:/tmp claude

View original on GitHub ↗

12 Comments

github-actions[bot] · 8 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/14242
  2. https://github.com/anthropics/claude-code/issues/11079
  3. https://github.com/anthropics/claude-code/issues/10194

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

hah23255 · 8 months ago

Comprehensive Root Cause Analysis and Fix Plan

Environment

  • Platform: Android/Termux (linux arm64)
  • Claude Code: 2.0.76
  • Node.js os.tmpdir(): Returns /data/data/com.termux/files/usr/tmp (correct)
  • TMPDIR env var: Set correctly by Termux

Root Cause Analysis

After deep investigation of cli.js, I identified 6 distinct hardcoded /tmp
patterns
:

| Pattern | Purpose | Count |
| ----------------------------------------- | ------------------------ | -------- |
| "/tmp/claude" | Main temp directory | Multiple |
| "/private/tmp/claude" | macOS alias | 1 |
| "/tmp/claude/" | Trailing slash variant | Multiple |
| "/tmp/claude_cli_latest_screenshot.png" | Screenshot capture | 1 |
| "/tmp/workspace" | Workspace sandbox | 1 |
| "TMPDIR=/tmp/claude" | Sandbox env override | 1 |

Critical Finding

The most problematic issue is in the sandbox environment setup function which
explicitly overrides TMPDIR:

// In yA1() function
let B = ["SANDBOX_RUNTIME=1", "TMPDIR=/tmp/claude"];

This means even though Termux correctly sets
TMPDIR=/data/data/com.termux/files/usr/tmp, the sandbox overwrites it with
the hardcoded /tmp/claude.

Why /tmp Fails on Termux

/tmp permissions: drwxrwx--x (0771)
/tmp owner:       shell:shell (UID 2000)
Termux user:      u0_a### (UID 10###)  [app-specific UID]
Result:           User has only 'x' (traverse), no 'rw' access

This is Android's security model - apps are sandboxed and cannot write to system
/tmp.

Affected Features

| Feature | Status | Reason |
| --------------------- | --------- | -------------------------------------------- |
| Main CLI | ✅ Works | Uses different path for CWD tracking |
| Task tool (subagents) | ❌ Broken | Tries /tmp/claude/.../tasks |
| Background agents | ❌ Broken | Same path issue |
| Explore agent | ❌ Broken | Same path issue |
| Screenshots | ❌ Broken | Uses /tmp/claude_cli_latest_screenshot.png |

Suggested Fix

Replace hardcoded paths with platform-aware paths using Node.js built-in:

const os = require("os");
const path = require("path");

// Option 1: Use os.tmpdir() which respects TMPDIR on all platforms
const CLAUDE_TMP = path.join(os.tmpdir(), "claude");

// Option 2: Explicit TMPDIR check with fallback
const CLAUDE_TMP = process.env.TMPDIR
  ? path.join(process.env.TMPDIR, "claude")
  : "/tmp/claude";

Critical: The sandbox TMPDIR override in yA1() should also use
os.tmpdir():

// Instead of: let B=["SANDBOX_RUNTIME=1","TMPDIR=/tmp/claude"];
const os = require("os");
let B = [`SANDBOX_RUNTIME=1`, `TMPDIR=${path.join(os.tmpdir(), "claude")}`];

Workaround (for affected users)

I've created an automated patch script that:

  1. Backs up cli.js with SHA256 verification
  2. Replaces all 6 hardcoded patterns
  3. Validates JavaScript syntax post-patch
  4. Runs verification tests
  5. Auto-detects npm updates and re-patches

The workaround is available but requires re-application after every npm
update
.

Recommendations for Official Fix

  1. Audit all /tmp references in the codebase
  2. Use os.tmpdir() consistently - it already respects TMPDIR on all

platforms

  1. Remove sandbox TMPDIR override or make it platform-aware
  2. Add Termux to CI testing if Android/Termux is a supported platform
  3. Consider XDG Base Directory spec for better cross-platform compatibility

Additional Context

  • Node.js os.tmpdir() on Termux correctly returns

/data/data/com.termux/files/usr/tmp

  • The issue affects any environment where /tmp has restricted permissions
  • This includes: Termux, some container environments, hardened Linux systems

I'm happy to help test any proposed fixes or provide additional debugging
information.

hah23255 · 8 months ago

Patch Implementation Update

Successfully implemented and tested automated patch solution:

Patch Statistics:

  • Patterns replaced: 11
  • Claude Code version: 2.0.76
  • Platform: Android/Termux arm64

Verification Results:

Test 1: No hardcoded /tmp paths     ✅ PASS (0 remaining)
Test 2: Termux paths present        ✅ PASS (10 references)
Test 3: JavaScript syntax valid     ✅ PASS
Test 4: Temp directory accessible   ✅ PASS

Replaced Patterns:
| Original | Count |
|----------|-------|
| "/tmp/claude" | 5 |
| "/tmp/claude/" | 1 |
| "/tmp/claude_cli_latest_screenshot.png" | 2 |
| "/private/tmp/claude" | 1 |
| "/tmp/workspace" | 1 |
| "TMPDIR=/tmp/claude" | 1 |

Automated Solution Features:

  1. SHA256-verified backups before patching
  2. JavaScript syntax validation post-patch
  3. Version tracking for npm update detection
  4. Auto-repatch on version/checksum change
  5. Complete rollback capability

The patch script is working reliably. Happy to share the implementation details if helpful for the official fix.

hah23255 · 8 months ago

Bug fix update: Patch script now preserves executable permissions.

Issue: mktemp creates files with 0600 perms. When mv replaces cli.js, the executable bit is lost, breaking the /usr/bin/claude symlink.

Fix: Added chmod 700 cli.js after mv in patch script.

This edge case only affects systems where cli.js is executed directly via symlink (like npm global installs).

hah23255 · 8 months ago

✅ Full Verification Complete

All previously blocked features now work after applying the patch:

| Feature | Before Patch | After Patch |
|---------|--------------|-------------|
| Task tool (subagents) | ❌ EACCES | ✅ Working |
| Background agents | ❌ EACCES | ✅ Working |
| Explore agent | ❌ EACCES | ✅ Working |
| Plan agent | ❌ EACCES | ✅ Working |
| General-purpose agent | ❌ EACCES | ✅ Working |
| Parallel agent spawning | ❌ EACCES | ✅ Working |
| Temp directory writes | ❌ EACCES | ✅ Working |

The root cause is confirmed: Hardcoded /tmp/claude paths fail on Termux due to Android's permission model. Replacing with os.tmpdir() or respecting TMPDIR env var resolves the issue completely.

Patch implementation archived for reference. Happy to assist with testing any official fix.

GGPrompts · 7 months ago

Thank you for sharing this. Can confirm the issue still exists.

Workaround
Using proot wrapper to bind mount tmp:

proot -b /data/data/com.termux/files/usr/tmp:/tmp claude

Worked for me!!

paperbenni · 7 months ago
Thank you for sharing this. Can confirm the issue still exists. `` Workaround Using proot wrapper to bind mount tmp: proot -b /data/data/com.termux/files/usr/tmp:/tmp claude `` Worked for me!!

This breaks rg for me

GGPrompts · 7 months ago
> Thank you for sharing this. Can confirm the issue still exists. > `` > Workaround > Using proot wrapper to bind mount tmp: > > proot -b /data/data/com.termux/files/usr/tmp:/tmp claude > `` > > > > > > > > > > > > Worked for me!! This breaks rg for me

We're saved!

Changelog
2.1.5
Added CLAUDE_CODE_TMPDIR environment variable to override the temp directory used for internal temp files, useful for environments with custom temp directory requirements

salviz · 7 months ago

Confirming: proot workaround is the ONLY working solution

Testing on Termux with properly configured environment variables:

# In ~/.profile (both directories exist and are writable)
export TMPDIR="$HOME/.cache/tmp"
export CLAUDE_CODE_TMPDIR="$HOME/.claude-tmp"

Result: Claude Code still fails with EACCES: permission denied, mkdir '/tmp/claude/...'

This confirms the path is hardcoded and ignores:

  • $TMPDIR
  • $CLAUDE_CODE_TMPDIR
  • os.tmpdir() in Node.js

Environment

  • Node.js v24.13.0, npm 11.8.0
  • Android 13 / Termux
  • All requirements exceeded

Confirmed Working Workaround

Your proot solution is currently the only working method:

proot -b /data/data/com.termux/files/usr/tmp:/tmp claude

Request

Can we get a status update on implementing proper $TMPDIR / os.tmpdir() support? There are now 8+ duplicate issues for this problem affecting all Termux users.

---
Tested and reported via Claude Code on Termux

github-actions[bot] · 6 months ago

Closing for now — inactive for too long. Please open a new issue if this is still relevant.

github-actions[bot] · 5 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.