expo / expo/eas-cli

eas workflow:run hangs indefinitely on non-TTY CI environments

Open
#3,774 0 comments 0 reactions 0 assignees View on GitHub
needs review
Dominant language
TypeScript
Stars
1.4k
Forks
236
Avg merge
3d 1h
Merged PRs (30d)
91

Description

### Build/Submit details page URL

_No response_

### Summary

## Symptom

When `eas workflow:run` is invoked on a CI agent without a controlling terminal, the command emits one line of output (`Using workflow file from …`) and then hangs indefinitely. No workflow run is ever created on the EAS side (verified via the dashboard). The same agent successfully runs `eas build` with identical flags.

Reproduced on Azure DevOps `ubuntu-latest` agents with `eas-cli` 19.x.

## Workaround

Redirect stdin from `/dev/null`:

```bash
npx eas workflow:run path/to/workflow.yml --non-interactive --json {
if (process.stdin.isTTY) {
return null;
}

return await new Promise((resolve, reject) => {
let data = '';
process.stdin.setEncoding('utf8');
process.stdin.on('readable', () => { /* … */ });
process.stdin.on('end', () => {
resolve(data.trim() || null);
});
process.stdin.on('error', err => reject(err));
});
}
```

On a CI agent stdin is typically connected to an open pipe from the agent harness — not a TTY, but never emits `'end'` either. The `await new Promise(...)` never resolves, the command hangs forever.

`eas build` does not have this issue because it does not call `maybeReadStdinAsync`; inputs come from flags only.

## Suggested fixes

Any of:

1. **Skip stdin reading entirely when `--non-interactive` is set.** Easiest fix.
2. **Skip stdin reading when no `--input` JSON is expected**, i.e. when all required inputs are provided via `-F` flags.
3. **Check `process.stdin.readableEnded` / `destroyed`** before attaching the listener, and short-circuit if stdin is unreadable.
4. **Apply a short timeout** to the stdin read (e.g. 1s) and fall back to `null` if no data arrives.

(Personally I'd combine 1+3 — `--non-interactive` is a clear signal not to expect stdin, and the readable-state check guards the remaining edge cases.)

### Managed or bare?

managed

### Environment

System:
OS: macOS 26.4
Shell: 5.9 - /bin/zsh
Binaries:
Node: 25.9.0 - /opt/homebrew/bin/node
Yarn: 1.22.22 - /opt/homebrew/bin/yarn
npm: 11.12.1 - /opt/homebrew/bin/npm
Watchman: 2026.03.30.00 - /opt/homebrew/bin/watchman
Managers:
CocoaPods: 1.16.2 - /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 25.4, iOS 26.4, macOS 26.4, tvOS 26.4, visionOS 26.4, watchOS 26.4
IDEs:
Android Studio: 2025.3 AI-253.30387.90.2532.14935130
Xcode: 26.4.1/17E202 - /usr/bin/xcodebuild
npmGlobalPackages:
eas-cli: 19.0.5
Expo Workflow: managed

### Error output

_No response_

### Reproducible demo or steps to reproduce from a blank project

See above

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.