mastra-ai/mastra · error · Error

Linear API error: ${body.errors[0]?.message ?? 'unknown erro

Error message

Linear API error: ${body.errors[0]?.message ?? 'unknown error'}

What it means

The `linearGraphql` helper throws this when Linear's GraphQL endpoint returns HTTP 200 but the response body contains a GraphQL `errors` array. Linear reports execution-level problems (validation errors, missing scopes, rate limits, bad UUIDs) this way even on 200 responses, and the integration surfaces the first error's `message` verbatim instead of the status code. It is a runtime API error from Linear's side, not a bug in your code.

Source

Thrown at mastracode/factory/src/integrations/linear/integration.ts:262

    body: JSON.stringify({ query, variables }),
  });
  if (!res.ok) {
    // Linear returns GraphQL errors (validation, missing scopes, …) with a
    // 400 status — surface the actual message instead of just the code.
    let detail: string | null = null;
    try {
      const errBody = (await res.json()) as { errors?: Array<{ message?: string }> };
      detail = errBody.errors?.[0]?.message ?? null;
    } catch {
      // Non-JSON error body; fall back to the status code alone.
    }
    const err = new Error(`Linear API request failed (${res.status})${detail ? `: ${detail}` : ''}`);
    (err as { status?: number }).status = res.status;
    throw err;
  }
  const body = (await res.json()) as { data?: T; errors?: Array<{ message?: string }> };
  if (body.errors?.length) {
    throw new Error(`Linear API error: ${body.errors[0]?.message ?? 'unknown error'}`);
  }
  if (!body.data) {
    throw new Error('Linear API returned no data.');
  }
  return body.data;
}

export class LinearIntegration implements FactoryIntegration {
  /** Stable integration identifier (see `../base.ts`). */
  readonly id = 'linear';
  /** Bound once by the factory via `initialize()` before any surface is used. */
  #storage: LinearStorageHandle | undefined;
  #projects: FactoryProjectsStorage | undefined;
  #auth: RouteAuth | undefined;

  /** Bind Linear's slice of the generic integration storage, the projects domain, and the host auth seam. */
  initialize({
    storage,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Read the message after the colon — it is Linear's own GraphQL error message and names the failing field/reason.
  2. If the message mentions permissions or scope, reconnect Linear and request the needed scope (e.g. `comments:create` for posting).
  3. If the message mentions an id or entity not found, verify you are passing Linear UUIDs, not human identifiers.
  4. If it is a rate-limit error, back off and retry with fewer concurrent GraphQL calls.
  5. If the message is 'unknown error', capture the full response body (e.g. via logging around `linearGraphql`) to see all `errors` entries.

Example fix

// before: human-readable identifier
await integration.getIssue({ connection, externalId: 'ENG-123' });
// after: Linear UUID from intake listItems metadata
await integration.getIssue({ connection, externalId: issue.externalId });
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight: ensure a connection exists and has the needed scope before calling
const conn = await integration.loadConnection(orgId);
if (!conn) throw new Error('Linear not connected');
if (mutation && !integration.canPostComments(conn)) throw new Error('Linear scope comments:create missing');

Type guard

function isLinearGraphqlError(err: unknown): err is Error & { linearMessage: string } {
  return err instanceof Error && err.message.startsWith('Linear API error: ');
}

Try / catch

try {
  const data = await linearGraphql<T>(token, query, variables);
} catch (err) {
  if (isLinearGraphqlError(err)) {
    const detail = err.message.slice('Linear API error: '.length);
    if (/permission|scope/i.test(detail)) promptReconnect();
    else if (/not found/i.test(detail)) fixExternalId();
    else if (/rate limit/i.test(detail)) scheduleRetryWithBackoff();
  }
  throw err;
}

Prevention

When it happens

Trigger: Any call routed through `linearGraphql` (e.g. `fetchWorkspace`, `listProjects`, `listActiveIssues`, `linear_create_comment`) where the response body has `errors[0].message` set: querying a non-existent issue UUID, using a token lacking the requested field's scope, malformed GraphQL query, or Linear-side rate limiting returned with a 200 status.

Common situations: Passing an issue id that is a display identifier (e.g. 'ENG-123') instead of a UUID; a connection granted only `read` scope attempting a comment mutation; Linear rate-limit errors after polling too aggressively; stale tokens revoked mid-flight.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/c924a933d2c62cac. Report an issue: GitHub.