{"record":{"id":"2f8c794ebfc4d152","repo":"affaan-m/ECC","slug":"from-is-required-for-handoffs","errorCode":null,"errorMessage":"--from is required for handoffs.","messagePattern":"--from is required for handoffs\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/memory.js","lineNumber":416,"sourceCode":"    throw new Error(\n      `memory ${command} is disabled in dry-run mode; no files were written.`\n    );\n  }\n}\n\nfunction runInitCommand({ command, options, positionals, roots }) {\n  requireNoPositionals(positionals, command);\n  return printInit(\n    initializeVault({ roots, scopes: options.scopes || undefined }),\n    options.json\n  );\n}\n\nfunction runWriteCommand({ command, options, positionals, roots }) {\n  requireNoPositionals(positionals, command);\n  if (!options.title) throw new Error('--title is required.');\n  if (command === 'handoff' && !options.from) {\n    throw new Error('--from is required for handoffs.');\n  }\n  if (command === 'handoff' && (!options.targets || options.targets.length === 0)) {\n    throw new Error('At least one --target is required for handoffs.');\n  }\n  return printWrite(\n    saveMemory(saveInput(options, command === 'handoff' ? 'handoff' : null), { roots }),\n    options.json\n  );\n}\n\nfunction runSearchCommand({ options, positionals, roots }) {\n  const query = positionals.join(' ');\n  return printSearch(query, searchMemories(query, {\n    roots,\n    scopes: options.scopes,\n    kinds: options.kinds,\n    targetHarness: options.targetHarness,\n    limit: options.limit,","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/memory.js#L398-L434","documentation":"Thrown by runWriteCommand in scripts/memory.js when the `handoff` subcommand is invoked without the `--from` flag. The memory CLI requires every handoff to declare its source harness so the resulting memory record is attributable. Without it the write is rejected before any file is touched.","triggerScenarios":"Running `node scripts/memory.js handoff --title \"X\" --target claude` while omitting `--from`. Also triggered when `--from` is set to an empty string, since the guard is a falsy check (`!options.from`) rather than a length check. The `save` subcommand does NOT require `--from` (it falls back to ECC_MEMORY_HARNESS env or 'unknown') — only `handoff` does.","commonSituations":"An agent or script wires up a handoff invocation and forgets the source harness flag; relying on the `save` command's fallback behavior and assuming `handoff` behaves the same; passing `--from=` with no value through a shell that swallows the empty token.","solutions":["Add `--from <harness-name>` (e.g. `--from claude`) to the handoff invocation.","Set the ECC_MEMORY_HARNESS environment variable as a fallback only if you intentionally want the `save` semantics — but note `handoff` still requires the explicit flag.","If scripting, assert the flag is non-empty before spawning the CLI to surface the error at the call site."],"exampleFix":"// before\nnode scripts/memory.js handoff --title \"Sync context\" --target claude\n// after\nnode scripts/memory.js handoff --from codex --title \"Sync context\" --target claude","handlingStrategy":"validation","validationCode":"function buildHandoffArgs({ from, title, targets }) {\n  if (!from || typeof from !== 'string') {\n    throw new Error('handoff requires a non-empty --from harness name');\n  }\n  if (!Array.isArray(targets) || targets.length === 0) {\n    throw new Error('handoff requires at least one --target harness');\n  }\n  if (!title) throw new Error('handoff requires --title');\n  return ['handoff', '--from', from, '--title', title, ...targets.flatMap(t => ['--target', t])];\n}","typeGuard":"function isHandoffInput(value) {\n  return (\n    value !== null &&\n    typeof value === 'object' &&\n    typeof value.from === 'string' && value.from.length > 0 &&\n    typeof value.title === 'string' && value.title.length > 0 &&\n    Array.isArray(value.targets) && value.targets.every(t => typeof t === 'string' && t.length > 0)\n  );\n}","tryCatchPattern":null,"preventionTips":["Validate the from/target/title triple in a builder function so the CLI is never invoked with missing required flags.","Treat handoff and save as distinct contracts — do not assume handoff inherits save's fallbacks.","In agent/tool wrappers, assert required flags before spawning the CLI to keep errors at the call site."],"tags":["cli","memory","argument-validation","handoff"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}