{"record":{"id":"90327c0e85062cf8","repo":"can1357/oh-my-pi","slug":"label-must-be-a-boolean","errorCode":null,"errorMessage":"${label} must be a boolean","messagePattern":"(.+?) must be a boolean","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/launch/protocol.ts","lineNumber":177,"sourceCode":"\treturn value;\n}\nfunction rawString(value: unknown, label: string): string {\n\tif (typeof value !== \"string\") throw new Error(`${label} must be a string`);\n\treturn value;\n}\n\nfunction optionalString(value: unknown, label: string): string | undefined {\n\tif (value === undefined) return undefined;\n\treturn stringValue(value, label);\n}\n\nfunction optionalRawString(value: unknown, label: string): string | undefined {\n\tif (value === undefined) return undefined;\n\treturn rawString(value, label);\n}\n\nfunction booleanValue(value: unknown, label: string): boolean {\n\tif (typeof value !== \"boolean\") throw new Error(`${label} must be a boolean`);\n\treturn value;\n}\n\nfunction numberValue(value: unknown, label: string): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) throw new Error(`${label} must be a finite number`);\n\treturn value;\n}\n\nfunction optionalNumber(value: unknown, label: string): number | undefined {\n\tif (value === undefined) return undefined;\n\treturn numberValue(value, label);\n}\n\nfunction stringArray(value: unknown, label: string): string[] {\n\tif (!Array.isArray(value)) throw new Error(`${label} must be an array of strings`);\n\tconst result: string[] = [];\n\tfor (const item of value) result.push(rawString(item, `${label} item`));\n\treturn result;","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/launch/protocol.ts#L159-L195","documentation":"Thrown by booleanValue(), the strict boolean validator for daemon protocol payloads. Any field parsed as a boolean (e.g. 'detached' in a spec, operation flags, snapshot fields) that arrives as anything other than true/false raises this. It guards against truthy/falsy values leaking across the daemon IPC boundary.","triggerScenarios":"Passing a payload to parseDaemonSpec, parseDaemonWireRequest, parseDaemonOperation, parseDaemonSnapshot, or parseDaemonRpcResult where a boolean field is 0/1, \"true\" (string), null, or missing (undefined) instead of an actual boolean.","commonSituations":"Config files using yes/no or 0/1 for booleans; query-string or CLI parsing that yields strings; a producer serializing 'detached: null' after failed initialization; schema drift between daemon versions.","solutions":["Read the label in the message to identify the offending field","Change the producer to emit a real JSON boolean (true/false)","Convert numeric/string flags at the producer boundary (Boolean(value) or value === \"true\")","If the field should be omittable, wrap with a default at the producer instead of sending undefined"],"exampleFix":"// before\nparseDaemonSpec({ id: \"d1\", command: [\"sleep\", \"1\"], detached: 1 })\n// after\nparseDaemonSpec({ id: \"d1\", command: [\"sleep\", \"1\"], detached: true })","handlingStrategy":"validation","validationCode":"function assertBooleanFields(obj: Record<string, unknown>, fields: string[]): void {\n  for (const f of fields) {\n    if (typeof obj[f] !== \"boolean\") throw new Error(`field '${f}' must be a boolean`);\n  }\n}\n// normalize first: obj.detached = obj.detached === 1 || obj.detached === \"true\";","typeGuard":"function isBoolean(v: unknown): v is boolean { return typeof v === \"boolean\"; }","tryCatchPattern":"try {\n  const spec = parseDaemonSpec(payload);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"must be a boolean\")) {\n    // coerce 0/1 and \"true\"/\"false\" strings at the producer and retry once\n  } else throw err;\n}","preventionTips":["Use real JSON booleans in configs (quote YAML \"no\"/\"yes\" values to avoid coercion)","Run payloads through a schema validator (zod/arktype) before parseDaemon*","Avoid passing CLI/query-string values directly — convert to booleans at the boundary","Type the payload with the exported DaemonSpec type before sending"],"tags":["validation","ipc","type-mismatch","boolean"],"backgroundTag":"schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}