Skip to content

CLI hangs after command completes when stdin is open but not a TTY #1206

@mattjames-canva

Description

@mattjames-canva

When running Apify CLI commands in a non-interactive environment where stdin is an open pipe (not a TTY and not closed), the process prints its output successfully but never exits. The Node process remains alive indefinitely.

This affects automation contexts such as CI runners, IDE agent shells, and other subprocess wrappers that connect stdin without providing a terminal.

Environment:

Apify CLI: 1.6.2 (installed via Homebrew)
OS: macOS (darwin, arm64)
Node: 26.3.0
Steps to reproduce:

Simulate a non-TTY environment with open stdin (e.g. pipe from a parent process)

In a context where stdin is connected but isatty(stdin) === false:

apify runs ls --limit 5

Table prints, then process hangs — no exit, no prompt return

Same command with stdin closed:

apify runs ls --limit 5 < /dev/null

Exits in ~5s with code 0

Also reproducible by spawning the CLI with open stdin from Node:

const { spawn } = require('child_process');
const p = spawn('apify', ['runs', 'ls', '--limit', '3'], {
stdio: ['pipe', 'pipe', 'pipe'], // stdin open, not a TTY
});
// Output completes, process never exits
const p2 = spawn('apify', ['runs', 'ls', '--limit', '3'], {
stdio: ['ignore', 'pipe', 'pipe'], // stdin ignored
});
// Exits normally with code 0
Expected behavior:

The CLI should exit cleanly after the command completes, regardless of whether stdin is a TTY. Other CLIs typically only read stdin when explicitly requested (e.g. via a flag like --input -) or when stdin is a TTY.

Actual behavior:

When stdin is an open non-TTY fd, the process hangs after printing output. The Node event loop appears to remain active — likely due to stdin middleware or a listener waiting on stdin that never receives EOF.

Workaround:

Redirect stdin from /dev/null for all non-interactive invocations:

apify runs ls < /dev/null
apify push < /dev/null
apify call my-actor -i '{}' < /dev/null
Impact:

This breaks scripted and automated use of the CLI in environments that don't provide a TTY but do leave stdin open (common in IDE agent shells, some CI wrappers, and subprocess spawners). The hang is silent — output looks complete — which makes it easy to miss and leaves orphaned processes accumulating.

Metadata

Metadata

Assignees

No one assigned

    Labels

    t-dxIssues owned by the DX team.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions