paperclipai/paperclip · error · PaperclipApiError

${method} ${path} failed with ${status}

Error message

${method} ${path} failed with ${status}

What it means

Same throw site as 450 (PaperclipApiError from requestJson on a non-OK response), but buildErrorMessage takes the shorter branch because the parsed body did not contain a string 'error' field — e.g. an empty body, plain text, or a JSON shape without 'error'. You still get status, method, and path on the error object, just no server message.

Source

Thrown at packages/mcp-server/src/client.ts:103

      Authorization: `Bearer ${this.config.apiKey}`,
      Accept: "application/json",
    };
    if (options.body !== undefined) {
      headers["Content-Type"] = "application/json";
    }
    if ((options.includeRunId ?? isWriteMethod(method)) && this.config.runId) {
      headers["X-Paperclip-Run-Id"] = this.config.runId;
    }

    const response = await fetch(url, {
      method,
      headers,
      body: options.body === undefined ? undefined : JSON.stringify(options.body),
    });
    const parsedBody = await parseResponseBody(response);

    if (!response.ok) {
      throw new PaperclipApiError({
        status: response.status,
        method: method.toUpperCase(),
        path,
        body: parsedBody,
        message: buildErrorMessage(method.toUpperCase(), path, response.status, parsedBody),
      });
    }

    return parsedBody as T;
  }
}

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Inspect the raw response — curl the same path directly to see the actual body.
  2. If a proxy is returning the error, fix the proxy/upstream config.
  3. On the client, read PaperclipApiError.body (parsedBody) for any non-'error' field that may carry detail.

Example fix

// status 502 with empty body -> 'GET /api/issues failed with 502'
// diagnose directly
curl -i -H "Authorization: Bearer $PAPERCLIP_API_KEY" $URL/api/issues
Defensive patterns

Strategy: try-catch

Type guard

function isPaperclipApiError(e: unknown): e is { status: number; method: string; path: string; body: unknown; message: string } {
  return typeof e === 'object' && e !== null && 'status' in e && typeof (e as any).status === 'number';
}

Try / catch

try { await client.requestJson(method, path, opts) }
catch (e) {
  if (isPaperclipApiError(e) && e.body == null && e.status >= 500) { /* likely proxy/upstream — do not retry blindly */ }
  throw e;
}

Prevention

When it happens

Trigger: Upstream returns non-2xx with an empty body (gateway/proxy 502/504), plain-text error from a reverse proxy, or a JSON envelope that uses a different key ('message', 'detail') than 'error'.

Common situations: A proxy in front of Paperclip returning HTML/text errors; the server crashed mid-request; a route that returns a non-standard error format.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/0bc35d9c4af13199. Report an issue: GitHub.