affaan-m/ECC · error · Error
Standard input remained unavailable after
Error message
Standard input remained unavailable after ${maxRetryWaitMs}ms. What it means
readBoundedStdin reads stdin with fs.readSync(0, ...). On non-blocking TTYs or interrupted reads the syscall can fail with EAGAIN/EWOULDBLOCK/EINTR; the function retries with delays up to maxRetryWaitMs. If stdin stays unavailable for the whole budget it throws 'Standard input remained unavailable after <maxRetryWaitMs>ms.' so callers know no body could be read.
Solutions
- Pipe the content explicitly: `echo "note" | node scripts/memory.js write --tags x` or `node scripts/memory.js write < body.txt`.
- When spawning the script programmatically, pass `stdio: 'inherit'` or provide a pipe with the body written and ended.
- When using docker, add `-i` (`docker run -i ...`) so stdin is attached.
- If retries are timing out under load, increase the retry budget (maxRetryWaitMs) in the script or pre-buffer stdin before invoking.
Example fix
// before node scripts/memory.js write --tags note # no stdin attached in CI // after echo "project decision" | node scripts/memory.js write --tags note
Defensive patterns
Strategy: retry
Validate before calling
if (process.stdin.isTTY && process.argv.includes('write') && !args.includes('--content')) {
console.error('This command reads stdin; pipe input or run interactively.');
} Try / catch
try { body = readBoundedStdin(limit); } catch (e) { if (e.message.includes('Standard input remained unavailable')) { console.error('stdin unavailable — pipe input, e.g. `echo x | memory write`, or attach stdio in your runner'); process.exitCode = 2; } else throw e; } Prevention
- Always pipe stdin when invoking memory write non-interactively
- Use stdio: 'inherit' or a provided pipe when spawning the script
- Add -i when running under docker
- Increase retry budget only after confirming stdin is actually expected
When it happens
Trigger: Running `node scripts/memory.js write` with no piped stdin in an environment where fd 0 is a non-blocking TTY (common in CI, docker run -t, or spawned processes without stdio inheritance).
Common situations: CI runners with detached stdin, `docker run` without `-i`, invoking the script from another tool that closes/doesn't forward stdin, or background jobs whose stdin is /dev/null with odd flags.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- Cannot read local asset
- capsule.write_failed
- download failed; existing destination preserved
- empty stdin
- ETIMEDOUT
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/7958b6002d28ae52.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/memory.js:175
&& retryOptions.maxRetryWaitMs >= 0
? retryOptions.maxRetryWaitMs
: MAX_STDIN_RETRY_WAIT_MS;
const wait = typeof retryOptions.wait === 'function'
? retryOptions.wait
: waitForStdinRetry;
const chunks = [];
let total = 0;
let remainingRetryWaitMs = maxRetryWaitMs;
while (total <= maxBytes) {
const buffer = Buffer.alloc(Math.min(64 * 1024, maxBytes + 1 - total));
let bytesRead;
try {
bytesRead = fs.readSync(0, buffer, 0, buffer.length, null);
} catch (error) {
const retryable = ['EAGAIN', 'EWOULDBLOCK', 'EINTR'].includes(error?.code);
if (!retryable) throw error;
if (remainingRetryWaitMs < retryDelayMs) {
throw new Error(
`Standard input remained unavailable after ${maxRetryWaitMs}ms.`
);
}
wait(retryDelayMs);
remainingRetryWaitMs -= retryDelayMs;
continue;
}
if (bytesRead === 0) break;
chunks.push(buffer.subarray(0, bytesRead));
total += bytesRead;
}
if (total > maxBytes) {
throw new Error(`memory body is too large (maximum ${maxBytes} bytes).`);
}
return decodeUtf8(Buffer.concat(chunks, total), 'memory body from standard input');
}
function readBody(options) {View on GitHub (pinned to 8321021c54)