{"record":{"id":"1681bc0c5d19fb4e","repo":"can1357/oh-my-pi","slug":"result-daemons-must-be-an-array","errorCode":null,"errorMessage":"result.daemons must be an array","messagePattern":"result\\.daemons must be an array","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/launch/protocol.ts","lineNumber":415,"sourceCode":"\t\tdefault:\n\t\t\tthrow new Error(`Unknown daemon operation: ${op}`);\n\t}\n}\n\n/** Decode a broker result using its pending operation as the discriminator. */\nexport function parseDaemonRpcResult(operation: DaemonOperation, value: unknown): DaemonRpcResult {\n\tconst source = record(value, `${operation.op} result`);\n\tswitch (operation.op) {\n\t\tcase \"ping\":\n\t\t\treturn { op: \"ping\", projectDir: stringValue(source.projectDir, \"result.projectDir\") };\n\t\tcase \"start\":\n\t\t\treturn {\n\t\t\t\top: \"start\",\n\t\t\t\tdaemon: parseDaemonSnapshot(source.daemon),\n\t\t\t\treadyTimedOut: booleanValue(source.readyTimedOut, \"result.readyTimedOut\"),\n\t\t\t};\n\t\tcase \"list\": {\n\t\t\tif (!Array.isArray(source.daemons)) throw new Error(\"result.daemons must be an array\");\n\t\t\treturn { op: \"list\", daemons: source.daemons.map(parseDaemonSnapshot) };\n\t\t}\n\t\tcase \"logs\":\n\t\t\treturn {\n\t\t\t\top: \"logs\",\n\t\t\t\tname: stringValue(source.name, \"result.name\"),\n\t\t\t\ttext: typeof source.text === \"string\" ? source.text : \"\",\n\t\t\t\tterminalRows:\n\t\t\t\t\tsource.terminalRows === undefined ? undefined : stringArray(source.terminalRows, \"result.terminalRows\"),\n\t\t\t\tterminalText:\n\t\t\t\t\tsource.terminalText === undefined ? undefined : rawString(source.terminalText, \"result.terminalText\"),\n\t\t\t\tcursor: numberValue(source.cursor, \"result.cursor\"),\n\t\t\t\ttimedOut: booleanValue(source.timedOut, \"result.timedOut\"),\n\t\t\t\tstate: daemonState(source.state),\n\t\t\t};\n\t\tcase \"wait\":\n\t\t\treturn {\n\t\t\t\top: \"wait\",","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/launch/protocol.ts#L397-L433","documentation":"parseDaemonRpcResult validates the `list` operation's result: `result.daemons` must be an array before each element is decoded into a daemon snapshot. A non-array means the broker returned a malformed or unexpected payload for the list call.","triggerScenarios":"Calling the list operation against a daemon whose response lacks `daemons`, sets it to null/an object, or whose protocol version shapes the result differently.","commonSituations":"Daemon/client version skew, a broker bug after an internal refactor, or intercepting/transforming socket traffic (proxy, logging shim) that mangles the envelope.","solutions":["Restart the daemon so its result shape matches the client's parser.","Inspect the raw result payload to see what `daemons` actually contains.","Update client and daemon to the same version.","If writing a mock/test broker, return `{ op: \"list\", daemons: [...] }` with daemons as an array of snapshot objects."],"exampleFix":"// before (mock broker)\nres({ op: \"list\", daemons: null });\n// after\nres({ op: \"list\", daemons: [snapshot] });","handlingStrategy":"validation","validationCode":"function isListResult(v: unknown): v is { op: \"list\"; daemons: unknown[] } {\n  return typeof v === \"object\" && v !== null && Array.isArray((v as any).daemons);\n}","typeGuard":"const hasDaemonsArray = (v: unknown): v is { daemons: unknown[] } =>\n  typeof v === \"object\" && v !== null && Array.isArray((v as { daemons?: unknown }).daemons);","tryCatchPattern":"try {\n  const result = await broker.list();\n} catch (err) {\n  if (err.message.includes(\"result.daemons must be an array\")) {\n    logger.warn(\"broker returned malformed list result\");\n    return [];\n  }\n  throw err;\n}","preventionTips":["Version-gate protocol result shapes","Test mock brokers against the real parser","Log raw results on parse failure","Keep daemon and client builds in lockstep"],"tags":["protocol","validation","daemon","ipc"],"backgroundTag":"schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}