Why track errors?
A high error rate on a specific feature often means a prompt is hitting the model's context window, a user is triggering safety filters, or you're exhausting provider rate limits. Seeing these events alongside cost data in FluxGate lets you catch regressions before they affect revenue.
Automatic tracking (provider wrappers)
When using @fluxgate/openai, @fluxgate/anthropic, or @fluxgate/gemini, errors are recorded automatically. You do not need to catch and re-record them — just let the exception propagate.
// The wrapper records status: "ERROR" before the exception surfaces
try {
const completion = await openai
.withContext({ feature: "code-review" })
.chat.completions.create({ model: "gpt-4o", messages });
} catch (err) {
// FluxGate already recorded the event.
// Handle the error for your user here.
return { error: "AI service temporarily unavailable." };
}
Manual error tracking (core SDK)
If you call LLM providers directly (no wrapper), use fg.recordEvent with an explicit status object:
import { fg } from "@/lib/fluxgate";
const startedAt = performance.now();
try {
const response = await myLLMProvider.call(prompt);
await fg.recordEvent({
usage: {
model: response.model,
provider: "custom",
inputTokens: response.inputTokens,
outputTokens: response.outputTokens,
latencyInMs: performance.now() - startedAt,
},
status: "SUCCESS",
metadata: { feature: "my-feature", user: session.user.id },
});
return response.text;
} catch (err: any) {
await fg.recordEvent({
usage: {
model: "unknown",
provider: "custom",
inputTokens: 0,
outputTokens: 0,
latencyInMs: performance.now() - startedAt,
},
status: {
status: "ERROR",
errorMessage: err.message ?? "Unknown error",
},
metadata: { feature: "my-feature", user: session.user.id },
});
throw err;
}
Status types and when to use each
| Status | When to use |
|---|---|
SUCCESS | Call completed normally |
ERROR | Network error, provider API error, or unhandled exception |
BLOCKED | Content was blocked by the model or a safety layer before tokens were generated |
MAX_TOKENS | Response was cut off because max_tokens was reached |
CONTENT_FILTER | Provider-side content filter triggered |
RECITATION | Model refused due to copyright recitation risk (Gemini) |
MALFORMED_REQUEST | Your request payload was invalid |
Tracking rate limit retries
If you retry on 429 Too Many Requests, record each attempt separately so you can see the retry overhead in your latency data:
import { fg } from "@/lib/fluxgate";
import { openai } from "@/lib/openai";
async function withRetry(messages: Message[], feature: string, userId: string) {
const maxAttempts = 3;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await openai
.withContext({ feature, user: userId })
.chat.completions.create({ model: "gpt-4o", messages });
} catch (err: any) {
const isRateLimit = err?.status === 429;
if (!isRateLimit || attempt === maxAttempts) throw err;
// Record the rate-limited attempt so it's visible in FluxGate
await fg.recordEvent({
usage: { inputTokens: 0, outputTokens: 0 },
status: { status: "ERROR", errorMessage: "429 rate limit — retrying" },
metadata: { feature, user: userId },
});
// Exponential back-off: 1 s, 2 s, 4 s
await new Promise((r) => setTimeout(r, 1000 * 2 ** (attempt - 1)));
}
}
}
Content filter tracking (Gemini safety)
Gemini returns a SAFETY finish reason when a response is blocked. The @fluxgate/gemini wrapper maps this to status: "BLOCKED" automatically.
const result = await geminiPro
.withContext({ feature: "user-content-gen", user: session.user.id })
.generateContent(userPrompt);
const tracking = result.fluxGateCostTrackingResponse;
if (tracking.status === "BLOCKED") {
// The event is already recorded in FluxGate with status "BLOCKED"
return { error: "Your request was blocked by content safety filters." };
}
return result.response.text();
Setting up an alert for error spikes
Once errors are flowing into FluxGate, create an alert so you're notified when the error rate climbs:
- Open Alerts → Create Alert on the dashboard.
- Set Metric to
requestCount(filter bystatus = ERROR). - Set Threshold to a count that indicates an anomaly (e.g.
> 50in a 1-hour window). - Add your preferred notification channel (email, Slack, Telegram).