affaan-m/ECC · warning
empty stdin
Error message
empty stdin
What it means
The `ck save` command reads its JSON payload from stdin (file descriptor 0) with readFileSync(0). Before JSON.parse runs, it trims the raw input and throws 'empty stdin' when nothing (or only whitespace) was piped in. The surrounding try/catch distinguishes 'caller sent nothing' from 'caller sent malformed JSON' and prints the expected schemas for both save and --init modes before exiting 1.
Source
Thrown at skills/ck/commands/save.mjs:34
* exit 0: success exit 1: error
*/
import { readFileSync, mkdirSync, writeFileSync } from 'fs';
import { resolve } from 'path';
import {
readProjects, writeProjects, loadContext, saveContext,
today, shortId, gitSummary, nativeMemoryDir,
CURRENT_SESSION,
} from './shared.mjs';
const isInit = process.argv.includes('--init');
const cwd = process.env.PWD || process.cwd();
// ── Read JSON from stdin ──────────────────────────────────────────────────────
let input;
try {
const raw = readFileSync(0, 'utf8').trim();
if (!raw) throw new Error('empty stdin');
input = JSON.parse(raw);
} catch (e) {
console.error(`ck save: invalid JSON on stdin — ${e.message}`);
console.log('Expected schema (save): {"summary":"...","leftOff":"...","nextSteps":["..."],"decisions":[{"what":"...","why":"..."}],"blockers":["..."]}');
console.log('Expected schema (--init): {"name":"...","path":"...","description":"...","stack":["..."],"goal":"...","constraints":["..."]}');
process.exit(1);
}
// ─────────────────────────────────────────────────────────────────────────────
// INIT MODE: first-time project registration
// ─────────────────────────────────────────────────────────────────────────────
if (isInit) {
const { name, path: projectPath, description, stack, goal, constraints, repo } = input;
if (!name || !projectPath) {
console.log('ck init: name and path are required.');
process.exit(1);
}View on GitHub (pinned to d8409a4b08)
Solutions
- Pipe a valid JSON payload matching the printed schema: echo '{"summary":"...","leftOff":"...","nextSteps":[],"decisions":[],"blockers":[]}' | ck save
- If using --init, pipe the init schema instead: echo '{"name":"...","path":"...","description":"...","stack":[],"goal":"...","constraints":[]}' | ck save --init
- When scripting it, guard the variable first: [ -n "$PAYLOAD" ] && ck save <<<"$PAYLOAD"
- Use a heredoc for long payloads: ck save <<'EOF' ... EOF, and check the exit code (1 means the payload never arrived or failed to parse)
Example fix
// before
$ ck save // no pipe -> "empty stdin", exit 1
// after
$ echo '{"summary":"fixed auth bug","leftOff":"tests green","nextSteps":["deploy"],"decisions":[],"blockers":[]}' | ck save Defensive patterns
Strategy: validation
Validate before calling
# bash: guarantee non-empty, valid JSON before invoking ck save
PAYLOAD=$(jq -nc --arg s "summary" --arg l "leftOff" '{summary:$s, leftOff:$l, nextSteps:[], decisions:[], blockers:[]}')
[ -n "$PAYLOAD" ] && jq -e . >/dev/null <<<"$PAYLOAD" && ck save <<<"$PAYLOAD" Prevention
- Always invoke ck save with a pipe or heredoc, never bare; treat bare invocation as a usage error
- Build payloads with jq -nc so they are non-empty and valid JSON by construction
- In scripts, check the exit code: 1 with the 'invalid JSON on stdin' banner means the payload never arrived or did not parse
- When wrapping ck in another process, make sure stdin is piped through (stdio: 'pipe' in Node's spawn), not inherited-closed
When it happens
Trigger: Running `ck save` or `ck save --init` interactively with no pipe or heredoc attached; piping only whitespace (`echo "" | ck save`); invoking from a script where the JSON variable is unset or empty (`echo "$PAYLOAD" | ck save` with PAYLOAD unset); a wrapper process that spawns ck save without forwarding stdin.
Common situations: Shell scripts building the payload into a variable that a set -u / typo mistake left empty; CI jobs piping the output of a failed earlier command (`cat missing.json | ck save` yields empty stdin); testing the command by running it bare to see usage; calling it via subprocess with stdio closed instead of piped.
Related errors
- Unknown argument: ${arg}
- Unknown argument: ${arg}
- Catalog show requires an install component ID
- Unknown catalog command: ${options.command}
- Unknown argument: ${arg}
AI-assisted analysis of affaan-m/ECC@d8409a4b08 (2026-08-26).
Data as JSON: /api/errors/b85403a837650af0.
Report an issue: GitHub.