{"record":{"id":"a79f8806de7ccd45","repo":"nexu-io/open-design","slug":"proposal-body-is-required","errorCode":null,"errorMessage":"proposal body is required","messagePattern":"proposal body is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/daemon/src/automation-proposals.ts","lineNumber":77,"sourceCode":"}\n\nexport async function getAutomationProposal(\n  dataDir: string,\n  id: string,\n): Promise<AutomationEvolutionProposal | null> {\n  const proposals = await listAutomationProposals(dataDir, { status: 'all' });\n  return proposals.find((proposal) => proposal.id === id) ?? null;\n}\n\nexport async function createAutomationProposal(\n  dataDir: string,\n  input: CreateAutomationEvolutionProposalRequest & {\n    id?: string;\n    status?: AutomationProposalStatus;\n  },\n): Promise<AutomationEvolutionProposal> {\n  const now = new Date().toISOString();\n  if (!input || typeof input !== 'object') throw new Error('proposal body is required');\n  if (typeof input.title !== 'string' || !input.title.trim()) {\n    throw new Error('proposal title is required');\n  }\n  if (typeof input.summary !== 'string' || !input.summary.trim()) {\n    throw new Error('proposal summary is required');\n  }\n  if (!input.patch || typeof input.patch !== 'object') {\n    throw new Error('proposal patch is required');\n  }\n  const status =\n    input.status && VALID_STATUSES.has(input.status)\n      ? input.status\n      : 'pending-review';\n  const proposal: AutomationEvolutionProposal = {\n    id:\n      typeof input.id === 'string' && input.id.trim()\n        ? input.id.trim()\n        : `proposal_${randomUUID()}`,","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/automation-proposals.ts#L59-L95","documentation":"Thrown by createAutomationProposal() as the first guard when the input argument is falsy or not an object. It is the top-level body-presence check that runs before field validation (title, summary, patch).","triggerScenarios":"Calling createAutomationProposal() directly or via POST to the proposals endpoint with null, undefined, a primitive, or an unparsed JSON string.","commonSituations":"Route handler missing body-parsing middleware; programmatic caller passing a serialized string; chained caller that conditionally built the body and ended up undefined.","solutions":["Pass a parsed object containing at least title, summary, and patch.","Ensure the HTTP layer applies JSON body parsing before reaching the service.","If constructing the input conditionally, default to an early return when fields are missing."],"exampleFix":"// before\nawait createAutomationProposal(dataDir, null);\n// after\nawait createAutomationProposal(dataDir, { title: 'T', summary: 'S', targetKind: 'memory-node', action: 'create', patch: { format: 'json', after: '{}' } });","handlingStrategy":"type-guard","validationCode":"if (!input || typeof input !== 'object') {\n  throw new Error('proposal body is required');\n}","typeGuard":"function isProposalInput(value: unknown): value is Record<string, unknown> {\n  return !!value && typeof value === 'object' && !Array.isArray(value);\n}","tryCatchPattern":null,"preventionTips":["Parse the request body as JSON before reaching the service.","Construct the input as an object literal, not a serialized string.","Guard conditionally-built inputs before calling."],"tags":["automation","proposals","validation","api","daemon"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}