{"record":{"id":"97936beb4027f323","repo":"nexu-io/open-design","slug":"automation-template-must-be-an-object","errorCode":null,"errorMessage":"automation template must be an object","messagePattern":"automation template must be an object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/daemon/src/automation-templates.ts","lineNumber":233,"sourceCode":"  }\n  return out.length > 0 ? out : fallback;\n}\n\nfunction cleanReviewPolicy(value: unknown): AutomationReviewPolicy {\n  return typeof value === 'string' && REVIEW_POLICIES.has(value as AutomationReviewPolicy)\n    ? value as AutomationReviewPolicy\n    : 'always';\n}\n\nfunction cleanCompressionMode(value: unknown): AutomationTokenCompressionMode {\n  return typeof value === 'string' && COMPRESSION_MODES.has(value as AutomationTokenCompressionMode)\n    ? value as AutomationTokenCompressionMode\n    : 'balanced';\n}\n\nexport function normalizeAutomationTemplate(input: unknown): AutomationTemplate {\n  if (!input || typeof input !== 'object' || Array.isArray(input)) {\n    throw new Error('automation template must be an object');\n  }\n  const raw = input as Record<string, unknown>;\n  const id = cleanId(raw.id);\n  if (!id) throw new Error('automation template id must be a safe slug');\n  const rawStages = Array.isArray(raw.stages) ? raw.stages : [];\n  const stages = rawStages\n    .map((stage): AutomationTemplate['stages'][number] | null => {\n      if (!stage || typeof stage !== 'object' || Array.isArray(stage)) return null;\n      const stageRaw = stage as Record<string, unknown>;\n      const stageId = cleanId(stageRaw.id);\n      const kind = stageRaw.kind;\n      const title = stageRaw.title;\n      if (!stageId || typeof title !== 'string' || !title.trim()) return null;\n      if (typeof kind !== 'string' || !STAGE_KINDS.has(kind as AutomationTemplateStageKind)) {\n        return null;\n      }\n      return {\n        id: stageId,","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/automation-templates.ts#L215-L251","documentation":"Thrown at the very top of normalizeAutomationTemplate when the input is not a plain object. null, undefined, arrays, strings, numbers, and booleans are all rejected before any field is read. This guards the entire shape so downstream field access (raw.id, raw.stages, ...) is safe.","triggerScenarios":"POSTing a template as a JSON array ([{...}]) instead of a single object; double-encoding the body so it arrives as a JSON string; passing undefined from a CLI flag that took no value; sending a top-level array of stages.","commonSituations":"A CLI wrapping the payload in an extra set of brackets; a fetch client sending JSON.stringify([{...}]) by mistake; the consumer iterating a list and accidentally passing the list instead of an element.","solutions":["Pass a single plain object, not an array and not a string.","Confirm the request uses Content-Type: application/json and that the daemon parsed the body (not received as a raw string).","If you intended to upsert several templates, loop and call upsert once per item rather than passing the array."],"exampleFix":"// before\nawait upsertUserAutomationTemplate(dataDir, [{ id: 'x', title: 'X', /* ... */ }]);\n\n// after\nawait upsertUserAutomationTemplate(dataDir, { id: 'x', title: 'X', /* ... */ });","handlingStrategy":"type-guard","validationCode":"function isPlainObject(v: unknown): v is Record<string, unknown> {\n  return v !== null && typeof v === 'object' && !Array.isArray(v);\n}\nif (!isPlainObject(payload)) throw new Error('Template payload must be a single object, not an array or primitive.');","typeGuard":"function isAutomationTemplateInput(v: unknown): v is Record<string, unknown> {\n  return v !== null && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  await upsertUserAutomationTemplate(dataDir, payload);\n} catch (err) {\n  if (err instanceof Error && err.message === 'automation template must be an object') {\n    return badRequest('Send a single template object, not an array or string.');\n  }\n  throw err;\n}","preventionTips":["Send a single object literal, not an array wrapper.","Ensure the HTTP client uses Content-Type: application/json and that the body is parsed, not double-encoded.","When bulk-importing, iterate the list and call upsert per item."],"tags":["automation","validation","templates"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}