paperclipai/paperclip · error

Empty AgentMail response

Error message

Empty AgentMail response

What it means

The AgentMail API client's request method streams the response body, and it throws this error when the HTTP response is not a 204 but has no body at all (response.body is null/undefined). Since a non-204 AgentMail response is expected to carry a JSON payload, an empty body indicates a truncated or malformed response from the upstream AgentMail service, and parsing cannot proceed.

Solutions

  1. Retry the request — this is usually a transient upstream/proxy issue; the client may already back off on some statuses, but an empty-body 200 warrants a manual retry.
  2. Check AgentMail service status and any intermediary proxy logs for truncated responses.
  3. Reduce intermediary buffering/timeouts that could terminate the body stream early.
  4. If persistent, capture the response status/headers and report the issue to the AgentMail provider.

Example fix

// before
const data = await agentmailApi(client).request("GET", "/v1/threads");
// after
let data;
for (let attempt = 0; attempt < 3; attempt++) {
  try { data = await agentmailApi(client).request("GET", "/v1/threads"); break; }
  catch (e) {
    if (e.message === "Empty AgentMail response" && attempt < 2) continue;
    throw e;
  }
}
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

null

Try / catch

try { return await api.request(method, path); }
catch (e) {
  if (e.message === "Empty AgentMail response") return withBackoffRetry(() => api.request(method, path));
  throw e;
}

Prevention

When it happens

Trigger: AgentMail returns a non-204 status with a null/empty body — e.g. a proxy or load balancer swallowing the body, an early connection close after headers, or a misbehaving AgentMail endpoint responding 200 with zero bytes.

Common situations: Reverse proxies (nginx/ALB) terminating the upstream connection mid-response; AgentMail service incident producing header-only responses; aggressive timeouts at an intermediary that drop the body but keep the status line.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/a6c1da4ce1e4f7b6. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/agentmail-api.ts:189

        Authorization: `Bearer ${apiKey}`,
        "Content-Type": "application/json",
        ...(idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}),
      },
      body: body === undefined ? undefined : JSON.stringify(body),
    });
    if (!response.ok) {
      const retryAfter = response.headers.get("retry-after");
      const seconds = Number(retryAfter ?? 1);
      const delay = Number.isFinite(seconds)
        ? seconds * 1000
        : Date.parse(retryAfter ?? "") - Date.now();
      throw new AgentmailApiError(
        response.status,
        Math.max(1000, Math.min(300_000, Number.isFinite(delay) ? delay : 1000)),
      );
    }
    if (response.status === 204) return undefined as T;
    if (!response.body) throw new Error("Empty AgentMail response");
    const reader = response.body.getReader();
    const parts: Uint8Array[] = [];
    let bytes = 0;
    try {
      for (;;) {
        const part = await reader.read();
        if (part.done) break;
        bytes += part.value.length;
        if (bytes > 16 * 1024 * 1024)
          throw new Error("AgentMail response exceeds the processing limit");
        parts.push(part.value);
      }
    } finally {
      await reader.cancel();
    }
    return JSON.parse(Buffer.concat(parts).toString("utf8")) as T;
  }
  const inboxPath = (id: string) => `/inboxes/${encodeURIComponent(id)}`;

View on GitHub (pinned to 3f1d897a7c)