CherryHQ/cherry-studio · error · Error

Invalid JSON from Feishu registration API: ${text.slice(0, 2

Error message

Invalid JSON from Feishu registration API: ${text.slice(0, 200)}

What it means

Thrown by postRegistration() in FeishuAppRegistration when the registration endpoint returns a body that JSON.parse cannot parse. The message includes the first 200 chars of the raw text for diagnosis. postRegistration POSTs URL-encoded params to the registration base URL.

Source

Thrown at src/main/ai/channels/adapters/feishu/FeishuAppRegistration.ts:51

type PollStatus = 'authorization_pending' | 'slow_down' | 'access_denied' | 'expired_token'

async function postRegistration(baseUrl: string, params: Record<string, string>): Promise<Record<string, unknown>> {
  const url = `${baseUrl}/oauth/v1/app/registration`
  // The Feishu registration API requires application/x-www-form-urlencoded,
  // matching the format used by @larksuiteoapi/openclaw-lark-tools.
  const body = new URLSearchParams(params).toString()
  const res = await net.fetch(url, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body
  })

  const text = await res.text()
  try {
    return JSON.parse(text) as Record<string, unknown>
  } catch {
    throw new Error(`Invalid JSON from Feishu registration API: ${text.slice(0, 200)}`)
  }
}

export async function registrationBegin(domain: FeishuDomain): Promise<RegistrationBeginResult> {
  const baseUrl = BASE_URLS[domain]

  // Step 1: init — check supported auth methods
  const initRes = await postRegistration(baseUrl, { action: 'init' })
  logger.info('Feishu registration init response', { supported: initRes })

  // Step 2: begin — start device flow
  const res = await postRegistration(baseUrl, {
    action: 'begin',
    archetype: 'PersonalAgent',
    auth_method: 'client_secret',
    request_user_info: 'open_id'
  })

View on GitHub (pinned to 726446b54c)

Solutions

  1. Inspect the first 200 chars in the message — HTML typically indicates a proxy/captive portal or wrong host.
  2. Verify BASE_URLS for the chosen FeishuDomain (feishu/lark) point at the live registration API host.
  3. Ensure outbound network from the host allows the registration endpoint without HTML interception.
  4. If text is empty, treat as a transient server fault and retry the registration call.
Defensive patterns

Strategy: retry

Validate before calling

// Sanity-check the registration endpoint reachability before the flow.
async function registrationEndpointHealthy(domain: FeishuDomain): Promise<boolean> {
  try {
    const res = await net.fetch(BASE_URLS[domain], { method: 'POST', body: new URLSearchParams({ action: 'init' }) })
    const text = await res.text()
    return text.trim().startsWith('{')
  } catch { return false }
}

Type guard

function isFeishuRegistrationJsonError(e: unknown): e is Error {
  return e instanceof Error && e.message.startsWith('Invalid JSON from Feishu registration API:')
}

Try / catch

try {
  await registrationBegin(domain)
} catch (e) {
  if (isFeishuRegistrationJsonError(e)) {
    notifyUser('Feishu registration endpoint unreachable (proxy/maintenance?)')
    return
  }
  throw e
}

Prevention

When it happens

Trigger: net.fetch to the registration URL succeeds (res completes) but res.text() is HTML (error page), plaintext, or empty, so JSON.parse throws.

Common situations: Corporate/MITM proxy returning an HTML block page, wrong BASE_URLS[domain] hitting a non-API host, Feishu maintenance page, or a redirect to a login HTML page.

Understand the failure class

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/8420383eb67bf117. Report an issue: GitHub.