{"record":{"id":"2b56f280134fb96d","repo":"tinyhumansai/openhuman","slug":"discord-link-complete-response-missing-required-bo","errorCode":null,"errorMessage":"Discord link complete response missing required boolean field: linked","messagePattern":"Discord link complete response missing required boolean field: linked","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/services/api/channelConnectionsApi.ts","lineNumber":90,"sourceCode":"  }\n  return record as T;\n}\n\nfunction expectDiscordLinkStart(payload: unknown): DiscordLinkStartResult {\n  const record = expectObject<Record<string, unknown>>(payload, 'Discord link start');\n  if (typeof record.linkToken !== 'string' || !record.linkToken) {\n    throw new Error('Discord link start response missing required string field: linkToken');\n  }\n  if (typeof record.instructions !== 'string') {\n    throw new Error('Discord link start response missing required string field: instructions');\n  }\n  return { linkToken: record.linkToken, instructions: record.instructions };\n}\n\nfunction expectDiscordLinkComplete(payload: unknown): DiscordLinkCheckResult {\n  const record = expectObject<Record<string, unknown>>(payload, 'Discord link complete');\n  if (typeof record.linked !== 'boolean') {\n    throw new Error('Discord link complete response missing required boolean field: linked');\n  }\n  const details =\n    record.details !== undefined && record.details !== null\n      ? (record.details as Record<string, unknown>)\n      : null;\n  return { linked: record.linked, details };\n}\n\nfunction normalizeConnectResult(payload: unknown): ChannelConnectionResult {\n  const record = expectObject<Record<string, unknown>>(payload, 'Channel connect');\n  const status = typeof record.status === 'string' ? record.status : '';\n  if (!status) {\n    throw new Error('Channel connect response missing status');\n  }\n  return {\n    status,\n    restart_required: Boolean(record.restart_required),\n    auth_action: typeof record.auth_action === 'string' ? record.auth_action : undefined,","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/app/src/services/api/channelConnectionsApi.ts#L72-L108","documentation":"Thrown by expectDiscordLinkComplete() when the Discord link-status RPC response's `linked` field is not a boolean. The complete/poll call answers with linked: true/false (plus optional details) to say whether the user finished DMing the token to the bot; any other type (missing, string 'true', number, null) fails this strict check before the UI can branch on the pairing state.","triggerScenarios":"Core returned an error-shaped record without linked; a string/number boolean encoding from an older core or a hand-rolled test mock; unwrapCliEnvelope peeled the wrong envelope layer so the record is the envelope, not the payload; details present but linked dropped during JSON restructuring.","commonSituations":"Polling loop for Discord pairing runs against a stale core after a partial app update; test mocks that use {linked: 'true'}; core handler evolved to return {status: 'linked'} style payloads on some paths.","solutions":["Restart/update the core so link.complete returns {linked: boolean, details?}.","Log the raw payload once at the failure point to see the actual type of `linked` and the record's keys.","Fix test/mocks to return a real boolean for linked.","If older cores legitimately send 'true'/'false' strings, coerce in the validator before the type check."],"exampleFix":"// before\nif (typeof record.linked !== 'boolean') {\n  throw new Error('Discord link complete response missing required boolean field: linked');\n}\n\n// after — coerce common encodings, still fail on genuinely missing data\nconst linked = typeof record.linked === 'boolean' ? record.linked\n  : record.linked === 'true' ? true\n  : record.linked === 'false' ? false\n  : null;\nif (linked === null) {\n  throw new Error('Discord link complete response missing required boolean field: linked');\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isDiscordLinkCompletePayload(v: unknown): v is { linked: boolean; details?: Record<string, unknown> | null } {\n  return typeof (v as { linked?: unknown } | null)?.linked === 'boolean';\n}","tryCatchPattern":"try {\n  const { linked } = await checkDiscordLink();\n} catch (e) {\n  if (e instanceof Error && e.message.includes('missing required boolean field: linked')) {\n    setStatus('unknown'); // stop polling, prompt user to relink\n  } else throw e;\n}","preventionTips":["Polling loops should stop and surface 'relink' on schema failure instead of retrying forever.","Return real booleans from mocks ({ linked: true }, not 'true').","Version-lock core and UI before testing channel linking."],"tags":["discord","channel-linking","schema-validation","boolean-field","core-rpc"],"backgroundTag":"schema-validation-failed","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}