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

  1. Pipe a valid JSON payload matching the printed schema: echo '{"summary":"...","leftOff":"...","nextSteps":[],"decisions":[],"blockers":[]}' | ck save
  2. If using --init, pipe the init schema instead: echo '{"name":"...","path":"...","description":"...","stack":[],"goal":"...","constraints":[]}' | ck save --init
  3. When scripting it, guard the variable first: [ -n "$PAYLOAD" ] && ck save <<<"$PAYLOAD"
  4. 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

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


AI-assisted analysis of affaan-m/ECC@d8409a4b08 (2026-08-26). Data as JSON: /api/errors/b85403a837650af0. Report an issue: GitHub.