{"record":{"id":"c6daa25d6abb1533","repo":"affaan-m/ECC","slug":"choose-exactly-one-memory-body-source-stdin-or","errorCode":null,"errorMessage":"Choose exactly one memory body source: --stdin or --body-file.","messagePattern":"Choose exactly one memory body source: --stdin or --body-file\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/memory.js","lineNumber":197,"sourceCode":"      wait(retryDelayMs);\n      remainingRetryWaitMs -= retryDelayMs;\n      continue;\n    }\n    if (bytesRead === 0) break;\n    chunks.push(buffer.subarray(0, bytesRead));\n    total += bytesRead;\n  }\n  if (total > maxBytes) {\n    throw new Error(`memory body is too large (maximum ${maxBytes} bytes).`);\n  }\n  return decodeUtf8(Buffer.concat(chunks, total), 'memory body from standard input');\n}\n\nfunction readBody(options) {\n  const sources = [Boolean(options.stdin), Boolean(options.bodyFile)]\n    .filter(Boolean).length;\n  if (sources !== 1) {\n    throw new Error('Choose exactly one memory body source: --stdin or --body-file.');\n  }\n  if (options.stdin) {\n    return readBoundedStdin(MAX_BODY_BYTES);\n  }\n\n  const bodyPath = path.resolve(options.bodyFile);\n  return readRegularTextFile(bodyPath, {\n    label: '--body-file',\n    maxBytes: MAX_BODY_BYTES,\n  });\n}\n\nfunction writeJson(payload) {\n  process.stdout.write(`${JSON.stringify(payload, null, 2)}\\n`);\n}\n\nfunction skipTerminalString(value, offset) {\n  let index = offset;","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/memory.js#L179-L215","documentation":"readBody requires exactly one memory body source: the CLI must receive either --stdin or --body-file, never both and never neither. It counts the truthy flags (filter(Boolean).length) and throws when the count is not 1. This removes ambiguity about where the memory content comes from.","triggerScenarios":"Running a save/write memory command with neither --stdin nor --body-file (sources === 0), or passing both flags in the same invocation (sources === 2). Raised in readBody, called from saveInput.","commonSituations":"Forgetting to redirect stdin (running `memory save --stdin` with no pipe AND no body); copy-pasting example commands that combine flags; shell scripts that conditionally add --stdin but leave --body-file set from a shared flag list.","solutions":["Pass exactly one source: either pipe content with `--stdin` or point `--body-file <path>` at an existing file, not both.","If you have both flags set by a wrapper script, strip one: choose --body-file for reproducible scripts, --stdin for ad-hoc pipes.","For empty/missing input, provide a file even if minimal rather than invoking with zero sources.","Wrap flag assembly in a small helper that asserts exactly one of the two flags is present before exec."],"exampleFix":"// before\necho \"notes\" | node scripts/memory.js save --stdin --body-file notes.md --title t\n// after\necho \"notes\" | node scripts/memory.js save --stdin --title t","handlingStrategy":"validation","validationCode":"const sourceCount = [Boolean(opts.stdin), Boolean(opts.bodyFile)].filter(Boolean).length;\nif (sourceCount !== 1) throw new Error('Provide exactly one of --stdin or --body-file.');","typeGuard":"function hasExactlyOneBodySource(o) {\n  return (typeof o.stdin === 'boolean') + (typeof o.bodyFile === 'string') === 1;\n}","tryCatchPattern":"try {\n  readBody(options);\n} catch (err) {\n  if (String(err.message).startsWith('Choose exactly one memory body source')) {\n    console.error('Pass either --stdin (piped) or --body-file <path>, not both/neither.');\n  } else throw err;\n}","preventionTips":["Standardize scripts on --body-file for reproducibility; reserve --stdin for interactive pipes.","Build CLI flags in one place so both flags can never be appended simultaneously.","Never invoke save/write commands without a body source; validate flags before exec."],"tags":["cli","argument-validation","mutually-exclusive"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}