[BUG] Claude CLI Hangs Without TTY Despite Using `-p` Flag

Resolved 💬 5 comments Opened Oct 6, 2025 by locactus Closed Jan 9, 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?

Environment

  • OS: macOS Darwin 24.6.0
  • Claude Code Version: 2.0.8
  • Java Version: OpenJDK 23.0.2
  • Execution Context: Java ProcessBuilder spawning Claude subprocess
  • TTY Status: No TTY (ps shows TTY = ??)

Problem Description

When running claude -p '<prompt>' from a Java application using ProcessBuilder:

  1. Claude process spawns successfully
  2. Process hangs indefinitely (no output, no termination)
  3. Process must be killed after timeout (30s in our case)
  4. Same command works perfectly when run manually in terminal

What Should Happen?

Expected Behavior

claude -p should:

  1. Execute the prompt non-interactively
  2. Print the response to stdout
  3. Exit with code 0
  4. Work without a TTY (as documented for print mode)

Actual Behavior

claude -p:

  1. Spawns successfully
  2. Hangs indefinitely
  3. Produces no stdout or stderr
  4. Must be forcibly terminated

Error Messages/Logs

Steps to Reproduce

Reproduction Steps

1. Terminal Execution (Works)

cd /path/to/working/dir
claude -p 'what is 2+2'
# Output: 4
# Exits immediately

2. Java ProcessBuilder Execution (Hangs)

ProcessBuilder processBuilder = new ProcessBuilder("claude", "-p", "what is 2+2")
    .directory(workingDir)
    .redirectErrorStream(false);

Process process = processBuilder.start();
boolean completed = process.waitFor(30, TimeUnit.SECONDS);
// completed = false (timeout after 30 seconds)
// No stdout, no stderr

3. Verification: Agent-app has no TTY

ps -o pid,tty,state,command -p <agent-pid>
# PID   TTY      STAT COMMAND
# 76254 ??       SN   /usr/bin/java ...agent-app.jar

4. Verification: Claude process has no TTY

ps -o pid,ppid,tty,state,command -p <claude-pid>
# PID  PPID  TTY   STAT COMMAND
# 78903 76254 ??   S+   claude -p what is 2+2

Expected Behavior

claude -p should:

  1. Execute the prompt non-interactively
  2. Print the response to stdout
  3. Exit with code 0
  4. Work without a TTY (as documented for print mode)

Actual Behavior

claude -p:

  1. Spawns successfully
  2. Hangs indefinitely
  3. Produces no stdout or stderr
  4. Must be forcibly terminated

Investigation Findings

What We Tried

  1. Removed JAVA_HOME - Ensured system /usr/bin/java is used (same as terminal)
  2. Cleaned PATH - Matched terminal environment exactly
  3. Environment variables - Set SHELL, HOME, USER, TMPDIR, LANG
  4. MCP config - Converted paths to absolute
  5. Killed suspended processes - Removed old suspended MCP servers
  6. Tested without MCP - Simple claude -p 'what is 2+2' also hangs

Evidence

2025-10-06T16:26:52.660+01:00  INFO ClaudeCommandService : Command: [claude, -p, what is 2+2]
2025-10-06T16:26:52.660+01:00  INFO ClaudeCommandService : Working Dir: /Users/.../68dac182f208810fecebe9b2
2025-10-06T16:26:52.660+01:00  INFO ClaudeCommandService : JAVA_HOME: null
2025-10-06T16:26:52.660+01:00  INFO ClaudeCommandService : PATH: /opt/anaconda3/bin:...
2025-10-06T16:26:52.660+01:00  INFO ClaudeCommandService : SHELL: /bin/zsh
2025-10-06T16:26:52.665+01:00  INFO ClaudeCommandService : Claude process started with PID: 78903
2025-10-06T16:27:22.670+01:00  WARN ClaudeCommandService : Claude process timed out after 30s; destroying...

Related Issues

Workarounds Considered

  1. PTY (pty4j) - Creates pseudo-terminal but risks SIGTTIN for MCP subprocesses
  2. script command - macOS utility to fake TTY: script -q /dev/null claude -p '...'
  3. unbuffer (expect) - Similar TTY simulation

Use Case

Building an infrastructure monitoring agent that:

  • Runs as background service (no TTY)
  • Executes Claude Code commands on behalf of users
  • Needs to integrate with MCP servers for task management
  • Must work non-interactively in automation scenarios

Impact

  • Severity: High - Blocks programmatic/automated use of Claude CLI
  • Scope: Affects any non-TTY execution context (daemons, CI/CD, batch jobs, etc.)
  • Workaround: None that properly solves MCP integration

Request

Please make claude -p mode truly non-interactive and TTY-independent as the flag suggests. The -p flag documentation implies it should work for scripting/automation, but it currently requires a TTY to function.

System Information

# macOS
Darwin 24.6.0

# Claude Code version
2.0.8 (Claude Code)

# Java
openjdk version "23.0.2"

# Terminal
/bin/zsh

Additional Context

This investigation took several hours and multiple approaches to isolate the issue. We initially suspected:

  • Path resolution issues
  • JAVA_HOME conflicts
  • MCP configuration problems
  • SIGTTIN signals from TTY inheritance

But ultimately proved that even the simplest claude -p command hangs without a TTY, indicating a fundamental issue with the CLI's TTY handling.

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

claude --version 2.0.8 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

_No response_

View original on GitHub ↗

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