diff --git a/src/app/api/plant-hours/import/route.ts b/src/app/api/plant-hours/import/route.ts index 68ba4d1..e36720c 100644 --- a/src/app/api/plant-hours/import/route.ts +++ b/src/app/api/plant-hours/import/route.ts @@ -47,22 +47,42 @@ const MAX_BYTES = 10 * 1024 * 1024; // 10 MB — same as fuel-logs import export async function POST(request: Request) { const start = Date.now(); - // PB's ClientResponseError has `.data` with field-level validation - // details. Plain `err.message` is just "Failed to create record." - - // useless for diagnosis. Flatten field-level detail into a single - // human-readable string so the operator can see which field is - // rejecting the row. + // PB's ClientResponseError has `.data` whose keys are "data", + // "message", "status" — only the inner `.data.data` (or sometimes + // `.data.data.fieldErrors`) holds the field-level validation object. + // Plain `err.message` is just "Failed to create record." - useless + // for diagnosis. Flatten the inner field-level detail into a single + // human-readable string so the operator can see WHICH field rejected + // the row. function formatPbError(err: unknown): string { const e = err as { message?: string; - data?: Record; + data?: { + data?: + | Record + | { + fieldErrors?: Record; + }; + message?: string; + }; }; const head = e?.message ?? "Insert failed"; - if (e?.data && typeof e.data === "object") { - const parts = Object.entries(e.data) - .map(([field, info]) => `${field}: ${info?.message ?? "invalid"}`) - .join("; "); - if (parts) return `${head} (${parts})`; + const inner = + e?.data?.data && typeof e.data.data === "object" ? e.data.data : null; + if (inner) { + const fieldErrors = + "fieldErrors" in inner && inner.fieldErrors ? inner.fieldErrors : inner; + if (typeof fieldErrors === "object" && fieldErrors !== null) { + const parts = Object.entries(fieldErrors as Record) + .map(([field, info]) => { + if (info && typeof info === "object" && "message" in info) { + return `${field}: ${(info as { message?: string }).message ?? "invalid"}`; + } + return `${field}: ${String(info)}`; + }) + .join("; "); + if (parts) return `${head} (${parts})`; + } } return head; }