mastra-ai/mastra · error
Invalid audit event response
Error message
Invalid audit event response
What it means
fetchAuditEvents validates the JSON body of a 200 response against the isAuditEventPage shape guard; if it doesn't match the expected audit-event page structure, it throws 'Invalid audit event response'. This protects callers from trusting a malformed payload (page metadata, event array, cursors).
Source
Thrown at mastracode/factory-ui/src/ui/domains/factory/services/audit.ts:124
baseUrl: string,
factoryProjectId: string,
options: { actions?: string[]; actorIds?: string[]; before?: string; limit?: number; signal?: AbortSignal } = {},
): Promise<AuditEventPage> {
const query = new URLSearchParams();
if (options.actions && options.actions.length > 0) query.set('actions', options.actions.join(','));
if (options.actorIds && options.actorIds.length > 0) query.set('actorIds', options.actorIds.join(','));
if (options.before) query.set('before', options.before);
if (options.limit) query.set('limit', String(options.limit));
const qs = query.size > 0 ? `?${query}` : '';
const res = await fetch(`${baseUrl}/web/factory/projects/${encodeURIComponent(factoryProjectId)}/audit${qs}`, {
headers: { Accept: 'application/json' },
credentials: 'include',
signal: options.signal,
});
if (!res.ok) return throwRequestError(res);
const data: unknown = await res.json();
if (!isAuditEventPage(data)) throw new Error('Invalid audit event response');
return data;
}
export async function fetchAuditPortalLink(baseUrl: string): Promise<string | null> {
const res = await fetch(`${baseUrl}/web/audit/portal-link`, {
headers: { Accept: 'application/json' },
credentials: 'include',
});
if (res.status === 404) return null;
if (!res.ok) return throwRequestError(res);
const data: unknown = await res.json();
if (typeof data !== 'object' || data === null || !('url' in data) || typeof data.url !== 'string') {
throw new Error('Invalid audit portal response');
}
return data.url;
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Log the failing body and compare it against isAuditEventPage's expected fields; fix whichever side drifted.
- Redeploy frontend and API together so the audit-events contract matches.
- Check for a proxy/gateway rewriting or caching a stale 200 response.
- Wrap the call defensively if you tolerate bad pages (e.g. show an empty state instead of throwing).
Example fix
// before (server)
return Response.json(events);
// after (server)
return Response.json({ events, nextCursor, hasMore }); // match isAuditEventPage Defensive patterns
Strategy: type-guard
Validate before calling
const res = await fetch(url);
if (!res.ok) throw new Error(`Audit events request failed: ${res.status}`);
const ct = res.headers.get('content-type') ?? '';
if (!ct.includes('application/json')) throw new Error('Audit endpoint returned non-JSON'); Type guard
function isAuditEventPage(v: unknown): v is AuditEventPage {
if (typeof v !== 'object' || v === null || !Array.isArray((v as any).events)) return false;
const o = v as Record<string, unknown>;
return (o.nextCursor === undefined || typeof o.nextCursor === 'string') && typeof o.hasMore === 'boolean';
} Try / catch
try {
const page = await fetchAuditEvents(baseUrl, projectId);
} catch (e) {
if (e instanceof Error && e.message === 'Invalid audit event response') {
console.error('Audit API contract drift — inspect raw body');
showEmptyState();
}
} Prevention
- Share the AuditEventPage type/schema between client and server.
- Snapshot-test the audit events endpoint response shape.
- Deploy frontend and API schema changes atomically.
- Guard against proxies serving stale cached 200s.
When it happens
Trigger: GET audit events returns 200 with JSON that fails isAuditEventPage — wrong/missing fields, events not an array, fields with wrong types — from an API version mismatch, a proxy substituting content, or a handler bug.
Common situations: Backend deployed with a changed audit-events schema while the frontend expects the old shape; CDN/HTML fallback served with 200; handler returning unwrapped data ({events} missing pagination fields).
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Invalid audit portal response
- Query parameter "status" must be "draft" or "published"
- Attention read-all response is missing its continuation curs
- Request failed (${res.status}) / server-provided message
- OpenAI Codex device authorization response missing required
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/8c1db1841dc4f9b4.
Report an issue: GitHub.