can1357/oh-my-pi · error · AnthropicStreamEnvelopeError

Anthropic cache refresh response omitted usage

Error message

Anthropic cache refresh response omitted usage

What it means

This AnthropicStreamEnvelopeError is thrown when the cache-refresh response body is a valid JSON object but has no parsable usage field. The whole point of the cache-refresh call is to obtain up-to-date token/cache usage numbers, so a response without usage is useless and the library fails rather than reporting zeros.

Source

Thrown at packages/ai/src/providers/anthropic.ts:2063

				};
				const request: unknown =
					isOAuthToken && client.beta
						? client.beta.messages.create(refreshParams, requestOptions)
						: client.messages.create(refreshParams, requestOptions);
				if (!hasAnthropicRawResponseRequest(request)) {
					throw new AIError.AnthropicStreamEnvelopeError(
						"Anthropic cache refresh request did not expose a raw response",
					);
				}
				const response = await request.asResponse();
				await notifyProviderResponse(options, response, model, response.headers.get("request-id"));
				const body: unknown = await response.json();
				if (!isRecord(body)) {
					throw new AIError.AnthropicStreamEnvelopeError("Anthropic cache refresh returned a malformed response");
				}
				const wireUsage = parseAnthropicWireUsage(body.usage);
				if (!wireUsage) {
					throw new AIError.AnthropicStreamEnvelopeError("Anthropic cache refresh response omitted usage");
				}
				if (typeof body.id === "string") output.responseId = body.id;
				output.usage.input = wireUsage.input_tokens ?? 0;
				output.usage.output = wireUsage.output_tokens ?? 0;
				output.usage.cacheRead = wireUsage.cache_read_input_tokens ?? 0;
				output.usage.cacheWrite = wireUsage.cache_creation_input_tokens ?? 0;
				applyAnthropicUsageExtras(output.usage, wireUsage);
				output.usage.totalTokens =
					output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
				calculateCost(model, output.usage);
				output.duration = performance.now() - startTime;
				stream.push({ type: "start", partial: output });
				stream.push({ type: "done", reason: "stop", message: output });
				stream.end();
				return;
			}

			// Opt-in flag: the response parser only honors `fallback` content

View on GitHub (pinned to 9690622007)

Solutions

  1. Ensure the endpoint is a genuine Anthropic Messages API that returns a usage object with input_tokens/output_tokens.
  2. If using a gateway/emulator, upgrade it to one that forwards the Anthropic usage fields.
  3. Check the configured API version header for schema changes to `usage`.
  4. Update test mocks to include usage: { input_tokens, output_tokens } (plus cache counters when relevant).

Example fix

// before
{ id: "msg_1", type: "message", role: "assistant" } // no usage

// after
{
  id: "msg_1", type: "message", role: "assistant",
  usage: { input_tokens: 10, output_tokens: 5, cache_read_input_tokens: 0, cache_creation_input_tokens: 0 },
}
Defensive patterns

Strategy: validation

Validate before calling

const body = await response.json();
const usage = body?.usage;
if (typeof usage !== "object" || usage === null ||
    (typeof usage.input_tokens !== "number" && typeof usage.output_tokens !== "number")) {
  throw new Error("Endpoint did not return Anthropic-style usage; check gateway/provider compatibility.");
}

Type guard

function hasWireUsage(body: unknown): body is { usage: { input_tokens?: number; output_tokens?: number; cache_read_input_tokens?: number; cache_creation_input_tokens?: number } } {
  return isRecord(body) && isRecord(body.usage) &&
    ("input_tokens" in body.usage || "output_tokens" in body.usage);
}

Try / catch

try {
  const usage = await refreshCacheUsage(params);
  return usage;
} catch (err) {
  if (err instanceof AIError.AnthropicStreamEnvelopeError && /omitted usage/.test(err.message)) {
    return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }; // degrade gracefully
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: The refresh response's `usage` field is missing, null, or lacks the expected counters (input_tokens/output_tokens) so parseAnthropicWireUsage returns null — e.g. a non-Anthropic endpoint or an error-shaped object returned with 200.

Common situations: Gateways that reshape or strip Anthropic responses; provider emulators (local LLM gateways) that omit usage; API version changes altering the usage schema; mocks that forget the usage object.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/a25958538730f159. Report an issue: GitHub.