Bug description
When an error is thrown from inside a model wrapped by withTracing (e.g. a GatewayResponseError from @ai-sdk/gateway carrying a cause chain), @posthog/ai serializes it via json.stringify() before storing it on the $ai_generation event's $ai_error property. Javascript error objects store properties like message, stack, and cause as non enumerable, so when serialized, usually only name remains.
The end result on the posthog dashboard is a stripped down error blob with no message, no stack, and no usable cause chain making it nearly impossible to debug what actually went wrong.
To reproduce
Tested against @posthog/ai@7.11.2 and @posthog/ai@7.18.1 same behaviour.
import { createGateway, generateText } from "ai";
import { withTracing } from "@posthog/ai";
import { PostHog } from "posthog-node";
const phClient = new PostHog(process.env.POSTHOG_KEY!, { host: process.env.POSTHOG_HOST });
const gateway = createGateway({ apiKey: process.env.AI_GATEWAY_API_KEY });
const tracedModel = withTracing(gateway("google/gemini-3-pro-image"), phClient, {
posthogDistinctId: "test-repro",
posthogTraceId: `test-repro-${Date.now()}`,
});
// Abort mid-stream to trigger a chained error from the gateway
const controller = new AbortController();
setTimeout(() => controller.abort(), 2000);
try {
await generateText({
model: tracedModel,
abortSignal: controller.signal,
messages: [
{ role: "user", content: "Generate a detailed photo of a sunset over snowy mountains." },
],
});
} catch (err) {
console.log("PostHog stores:", JSON.stringify(err));
console.log("Actual error:", {
name: (err as Error).name,
message: (err as Error).message,
cause: (err as { cause?: unknown }).cause,
});
}
await phClient.shutdown();
Output observed
{
"statusCode":500,
"cause":{},
"name":"GatewayResponseError",
"type":"response_error",
"response":{},
"validationError":{
"name":"AI_TypeValidationError",
"cause":{
"name":"ZodError",
"message":"[\n {\n "expected": "object",\n "code": "invalid_type",\n "path": [\n "error"\n ],\n "message": "Invalid input: expected object, received undefined"\n }\n]"
},
"value":{}
}
message and the cause chain's deeper fields are missing from $ai_error, even though they exist on the actual thrown error.
Related sub-libraries
Bug description
When an error is thrown from inside a model wrapped by withTracing (e.g. a GatewayResponseError from @ai-sdk/gateway carrying a cause chain), @posthog/ai serializes it via json.stringify() before storing it on the $ai_generation event's $ai_error property. Javascript error objects store properties like message, stack, and cause as non enumerable, so when serialized, usually only name remains.
The end result on the posthog dashboard is a stripped down error blob with no message, no stack, and no usable cause chain making it nearly impossible to debug what actually went wrong.
To reproduce
Tested against
@posthog/ai@7.11.2and@posthog/ai@7.18.1same behaviour.Output observed
message and the cause chain's deeper fields are missing from $ai_error, even though they exist on the actual thrown error.
Related sub-libraries