/* Copyright 2026 Marimo. All rights reserved. */ import { z } from "zod"; const DetailsSchema = z.object({ detail: z.string(), }); const ErrorSchema = z.object({ error: z.string(), }); export function prettyError(error: unknown): string { if (!error) { return "Unknown error"; } if (error instanceof Error) { const details = DetailsSchema.safeParse(error.cause); if (details.success) { return details.data.detail; } return maybeExtractDetails(error.message); } if (typeof error === "object") { const details = DetailsSchema.safeParse(error); if (details.success) { return details.data.detail; } const parsed = ErrorSchema.safeParse(error); if (parsed.success) { return parsed.data.error; } } try { return JSON.stringify(error); } catch { return String(error); } } function maybeExtractDetails(message: string): string { const parsed = safeJSONParse(message); if (!parsed) { return message; } const details = DetailsSchema.safeParse(parsed); if (details.success) { return details.data.detail; } const error = ErrorSchema.safeParse(parsed); if (error.success) { return error.data.error; } return message; } function safeJSONParse(message: string): unknown { try { return JSON.parse(message); } catch { return message; } } /** * A failed HTTP response. Carries the status code so callers can branch on it * (e.g. treat a capability 403 as a benign viewer state). The response body is * kept as `cause` so `prettyError` can surface its `detail`. */ export class HTTPError extends Error { public readonly status: number; public constructor(status: number, statusText: string, body?: unknown) { super(statusText, { cause: body }); this.name = "HTTPError"; this.status = status; } } export class CellNotInitializedError extends Error { public constructor( message = "The cell containing this UI element has not been run yet. Please run the cell first.", ) { super(message); this.name = "CellNotInitializedError"; } } export class FunctionNotFoundError extends Error { public constructor( message = "This UI element could not reach its function on the kernel. Try re-running the cell.", ) { super(message); this.name = "FunctionNotFoundError"; } } export class NoKernelConnectedError extends Error { public constructor(message = "Not yet connected to a kernel.") { super(message); this.name = "NoKernelConnectedError"; } }