Skip to content

Commit c836a85

Browse files
authored
🤖 fix: improve ORPC validation error logging (#1260)
Extract detailed Zod validation info from `EVENT_ITERATOR_VALIDATION_FAILED` errors instead of logging the generic 'Event iterator validation failed' message. ## Changes The new `formatValidationError()` helper extracts: - Validation issue paths and messages (up to 3) - Count of additional issues if more than 3 - Event type that failed validation ## Before ``` [WorkspaceStore] Error in onChat subscription for 6d48f6dc1c: ORPCError: Event iterator validation failed ``` ## After ``` [WorkspaceStore] Event validation failed for 6d48f6dc1c: type: Invalid discriminator value; metadata.usage.inputTokens: Expected number (+2 more) [event: stream-end] ``` --- _Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_
1 parent 13c0384 commit c836a85

File tree

1 file changed

+61
-9
lines changed

1 file changed

+61
-9
lines changed

src/browser/stores/WorkspaceStore.ts

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,18 @@ function createInitialChatTransientState(): WorkspaceChatTransientState {
242242
const ON_CHAT_RETRY_BASE_MS = 250;
243243
const ON_CHAT_RETRY_MAX_MS = 5000;
244244

245-
type IteratorValidationFailedError = Error & { code: "EVENT_ITERATOR_VALIDATION_FAILED" };
245+
interface ValidationIssue {
246+
path?: Array<string | number>;
247+
message?: string;
248+
}
249+
250+
type IteratorValidationFailedError = Error & {
251+
code: "EVENT_ITERATOR_VALIDATION_FAILED";
252+
cause?: {
253+
issues?: ValidationIssue[];
254+
data?: unknown;
255+
};
256+
};
246257

247258
function isIteratorValidationFailed(error: unknown): error is IteratorValidationFailedError {
248259
return (
@@ -251,6 +262,40 @@ function isIteratorValidationFailed(error: unknown): error is IteratorValidation
251262
);
252263
}
253264

265+
/**
266+
* Extract a human-readable summary from an iterator validation error.
267+
* ORPC wraps Zod issues in error.cause with { issues: [...], data: ... }
268+
*/
269+
function formatValidationError(error: IteratorValidationFailedError): string {
270+
const cause = error.cause;
271+
if (!cause) {
272+
return "Unknown validation error (no cause)";
273+
}
274+
275+
const issues = cause.issues ?? [];
276+
if (issues.length === 0) {
277+
return `Unknown validation error (no issues). Data: ${JSON.stringify(cause.data)}`;
278+
}
279+
280+
// Format issues like: "type: Invalid discriminator value" or "metadata.usage.inputTokens: Expected number"
281+
const issuesSummary = issues
282+
.slice(0, 3) // Limit to first 3 issues
283+
.map((issue) => {
284+
const path = issue.path?.join(".") ?? "(root)";
285+
const message = issue.message ?? "Unknown issue";
286+
return `${path}: ${message}`;
287+
})
288+
.join("; ");
289+
290+
const moreCount = issues.length > 3 ? ` (+${issues.length - 3} more)` : "";
291+
292+
// Include the event type if available
293+
const data = cause.data as { type?: string } | undefined;
294+
const eventType = data?.type ? ` [event: ${data.type}]` : "";
295+
296+
return `${issuesSummary}${moreCount}${eventType}`;
297+
}
298+
254299
function calculateOnChatBackoffMs(attempt: number): number {
255300
return Math.min(ON_CHAT_RETRY_BASE_MS * 2 ** attempt, ON_CHAT_RETRY_MAX_MS);
256301
}
@@ -1243,15 +1288,22 @@ export class WorkspaceStore {
12431288
return;
12441289
}
12451290

1246-
// EVENT_ITERATOR_VALIDATION_FAILED with ErrorEvent cause happens when:
1247-
// - The workspace was removed on server side (iterator ends with error)
1248-
// - Connection dropped (WebSocket/MessagePort error)
1249-
// Only suppress if workspace no longer exists (was removed during the race)
1250-
if (isIteratorValidationFailed(error) && !this.isWorkspaceSubscribed(workspaceId)) {
1251-
return;
1291+
// EVENT_ITERATOR_VALIDATION_FAILED can happen when:
1292+
// 1. Schema validation fails (event doesn't match WorkspaceChatMessageSchema)
1293+
// 2. Workspace was removed on server side (iterator ends with error)
1294+
// 3. Connection dropped (WebSocket/MessagePort error)
1295+
if (isIteratorValidationFailed(error)) {
1296+
// Only suppress if workspace no longer exists (was removed during the race)
1297+
if (!this.isWorkspaceSubscribed(workspaceId)) {
1298+
return;
1299+
}
1300+
// Log with detailed validation info for debugging schema mismatches
1301+
console.error(
1302+
`[WorkspaceStore] Event validation failed for ${workspaceId}: ${formatValidationError(error)}`
1303+
);
1304+
} else {
1305+
console.error(`[WorkspaceStore] Error in onChat subscription for ${workspaceId}:`, error);
12521306
}
1253-
1254-
console.error(`[WorkspaceStore] Error in onChat subscription for ${workspaceId}:`, error);
12551307
}
12561308

12571309
const delayMs = calculateOnChatBackoffMs(attempt);

0 commit comments

Comments
 (0)