stablyai/orca · error

GitLab returned an error: ${reported}

Error message

GitLab returned an error: ${reported}

What it means

Thrown by parseGlabJsonList when glab returned a JSON object (not an array) that carries a GitLab error envelope — specifically an object with a string `message` or `error` field. glab exits 0 on many error envelopes (and on proxy interstitials), so without this guard `JSON.parse(...).map` would throw an opaque `.map is not a function`. The reported text is truncated to REPORTED_PAYLOAD_LIMIT (300 chars).

Source

Thrown at src/main/gitlab/glab-api-response.ts:47

export class GlabNonListResponseError extends Error {}

// Why: glab allows a 10MB body; this is what keeps a proxy's whole response out of the error banner.
const REPORTED_PAYLOAD_LIMIT = 300

/**
 * Parse a glab list response, failing readably when GitLab answers with a JSON object.
 *
 * Why: glab exits 0 on error envelopes and proxy wrappers, so `JSON.parse(...).map` threw an
 * opaque `.map is not a function` that the caller's classifier could only report as "unknown".
 */
export function parseGlabJsonList<T>(payload: string): T[] {
  const parsed: unknown = JSON.parse(payload)
  if (Array.isArray(parsed)) {
    return parsed as T[]
  }
  const reported = gitlabErrorText(parsed)
  if (reported) {
    throw new Error(`GitLab returned an error: ${reported}`)
  }
  // Why: slice the raw payload rather than re-serializing `parsed` — same text, without
  // stringifying a multi-megabyte body just to keep the preview.
  throw new GlabNonListResponseError(
    `GitLab returned a non-list response: ${payload.trim().slice(0, REPORTED_PAYLOAD_LIMIT)}`
  )
}

/** GitLab reports API failures as `{ message }` or `{ error }`; anything else is opaque data. */
function gitlabErrorText(parsed: unknown): string | null {
  if (typeof parsed !== 'object' || parsed === null) {
    return null
  }
  const { message, error } = parsed as { message?: unknown; error?: unknown }
  for (const value of [message, error]) {
    if (typeof value === 'string' && value.trim()) {
      return value.trim().slice(0, REPORTED_PAYLOAD_LIMIT)
    }

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Read the reported text — it is the literal GitLab message and names the real cause (auth, scope, not-found, rate limit).
  2. Refresh the GitLab token / reconnect the integration if the message indicates 401/403.
  3. Verify the project path and endpoint path are correct for the target GitLab instance.
  4. If behind a proxy, confirm the proxy forwards the real GitLab response rather than its own error envelope.
Defensive patterns

Strategy: try-catch

Validate before calling

function looksLikeGitLabErrorEnvelope(payload: string): boolean {
  try {
    const v = JSON.parse(payload)
    return !Array.isArray(v) && typeof v === 'object' && v !== null
      && (typeof (v as any).message === 'string' || typeof (v as any).error === 'string')
  } catch { return false }
}

Type guard

function isGitLabErrorEnvelope(parsed: unknown): parsed is { message?: string; error?: string } {
  return typeof parsed === 'object' && parsed !== null
    && (typeof (parsed as any).message === 'string' || typeof (parsed as any).error === 'string')
}

Try / catch

try {
  const list = parseGlabJsonList<MrType>(payload)
  // use list
} catch (error) {
  if (error instanceof GlabNonListResponseError) { /* opaque, surface raw */ }
  else if (error instanceof Error && error.message.startsWith('GitLab returned an error:')) {
    // auth/scope/not-found — read message, refresh token or fix path
  } else throw error
}

Prevention

When it happens

Trigger: Any glab list command (`glab api projects/:id/merge_requests`, `glab mr list`, etc.) where GitLab responds with `{ "message": "..." }` or `{ "error": "..." }` but glab still exits 0. Common with 401/403/404 envelopes, rate-limit notices, and reverse-proxy error pages that pass through as JSON.

Common situations: Expired or revoked GitLab token (401 envelope); insufficient scope (403); project path/MR iid mismatch (404); GitLab self-hosted behind a proxy that returns its own JSON error; rate limiting (`{ message: "429 Too Many Requests" }`).

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/bfd03854ddcad548. Report an issue: GitHub.