tinyhumansai/openhuman · error

Discord link complete response missing required boolean fiel

Error message

Discord link complete response missing required boolean field: linked

What it means

Thrown by expectDiscordLinkComplete() while validating the 'openhuman.channels_discord_link_check' response: the payload object must contain 'linked' as a boolean (details is optional and tolerated as null/undefined). The polling loop in the Discord connect UI hits this when the core's link-check answer cannot be interpreted as a link state.

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 a221052e0d)

Solutions

  1. Restart the core / relaunch the app to resync frontend and core builds
  2. Curl openhuman.channels_discord_link_check with the pending linkToken and inspect the result object's shape
  3. Check core logs for link-token lookup failures (expired/garbage token) that may be surfaced as a degenerate payload
  4. If developing the handler, always include linked: bool in the response, even on lookup failure (linked: false + details.error)

Example fix

// before (core returns an error object through a success path)
{"error": "token not found"}

// after
{"linked": false, "details": {"error": "token not found"}}
Defensive patterns

Strategy: type-guard

Validate before calling

// Skip polling when the token is clearly invalid, so the check never runs against a dead token:
if (!linkToken.trim()) stopPolling();

Type guard

function isDiscordLinkCheck(v: unknown): v is { linked: boolean; details?: Record<string, unknown> | null } {
  const r = v as Record<string, unknown> | null | undefined;
  const inner =
    r && 'result' in r && 'logs' in r ? (r.result as Record<string, unknown>) : r;
  return !!inner && typeof inner.linked === 'boolean';
}

Try / catch

try {
  const { linked } = await channelConnectionsApi.discordLinkCheck(token);
  if (linked) finishLink();
} catch (e) {
  if (e instanceof Error && e.message.includes('linked')) {
    stopPollingAndWarn('Could not read link status — restart the app and relink.');
  } else throw e;
}

Prevention

When it happens

Trigger: discordLinkCheck(linkToken) resolves with a payload like {status: 'pending'}, {is_linked: true} (renamed field), {} (unknown/expired token handled by returning an empty object), or a CLI envelope whose result lacks a boolean 'linked'.

Common situations: Core/frontend version skew after a partial update; a Rust refactor renaming 'linked' or nesting it one level deeper; the link token expired and an older core returned an error-shaped object through a success path.

Related errors


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