tinyhumansai/openhuman · error

Discord link complete response missing required boolean…

Error message

Discord link complete response missing required boolean field: linked

What it means

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.

Solutions

  1. Restart/update the core so link.complete returns {linked: boolean, details?}.
  2. Log the raw payload once at the failure point to see the actual type of `linked` and the record's keys.
  3. Fix test/mocks to return a real boolean for linked.
  4. If older cores legitimately send 'true'/'false' strings, coerce in the validator before the type check.

Example fix

// before
if (typeof record.linked !== 'boolean') {
  throw new Error('Discord link complete response missing required boolean field: linked');
}

// after — coerce common encodings, still fail on genuinely missing data
const linked = typeof record.linked === 'boolean' ? record.linked
  : record.linked === 'true' ? true
  : record.linked === 'false' ? false
  : null;
if (linked === null) {
  throw new Error('Discord link complete response missing required boolean field: linked');
}
Defensive patterns

Strategy: type-guard

Type guard

function isDiscordLinkCompletePayload(v: unknown): v is { linked: boolean; details?: Record<string, unknown> | null } {
  return typeof (v as { linked?: unknown } | null)?.linked === 'boolean';
}

Try / catch

try {
  const { linked } = await checkDiscordLink();
} catch (e) {
  if (e instanceof Error && e.message.includes('missing required boolean field: linked')) {
    setStatus('unknown'); // stop polling, prompt user to relink
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/2b56f280134fb96d. Report an issue: GitHub.

Appendix: source

Thrown at app/src/services/api/channelConnectionsApi.ts:90

  }
  return record as T;
}

function expectDiscordLinkStart(payload: unknown): DiscordLinkStartResult {
  const record = expectObject<Record<string, unknown>>(payload, 'Discord link start');
  if (typeof record.linkToken !== 'string' || !record.linkToken) {
    throw new Error('Discord link start response missing required string field: linkToken');
  }
  if (typeof record.instructions !== 'string') {
    throw new Error('Discord link start response missing required string field: instructions');
  }
  return { linkToken: record.linkToken, instructions: record.instructions };
}

function expectDiscordLinkComplete(payload: unknown): DiscordLinkCheckResult {
  const record = expectObject<Record<string, unknown>>(payload, 'Discord link complete');
  if (typeof record.linked !== 'boolean') {
    throw new Error('Discord link complete response missing required boolean field: linked');
  }
  const details =
    record.details !== undefined && record.details !== null
      ? (record.details as Record<string, unknown>)
      : null;
  return { linked: record.linked, details };
}

function normalizeConnectResult(payload: unknown): ChannelConnectionResult {
  const record = expectObject<Record<string, unknown>>(payload, 'Channel connect');
  const status = typeof record.status === 'string' ? record.status : '';
  if (!status) {
    throw new Error('Channel connect response missing status');
  }
  return {
    status,
    restart_required: Boolean(record.restart_required),
    auth_action: typeof record.auth_action === 'string' ? record.auth_action : undefined,

View on GitHub (pinned to 7491200858)