You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When the server-side CSV parser throws, POST /api/csv/preview returns a structured error (the BUG-025 handler in api/routers/csv_routes.py):
{"status": "invalid_structure", "reason": "parse_failed", "message": "The CSV couldn't be parsed. Check the file's structure and try again."}
The frontend's csvPreviewResultSchema (csv-table-hub-main/src/lib/csv.functions.ts) only allowed reason: "empty" | "header_only" | "no_columns". So previewCsv() failed zod validation and threw Unexpected response shape from /api/csv/preview: reason: Invalid enum value….
Impact
In Uploader.handleFiles (src/routes/_authenticated/index.tsx), previewCsv is only used for the best-effort T&E table suggestion, and the exception is swallowed by catch { /* suggestion only */ }.
The visible effect: the user gets no T&E table suggestion and no explanation. The server's message never reaches the UI.
It is a contract mismatch between API and frontend: a valid API response is treated as malformed.
Steps to reproduce
Make the server parser throw on a file (in tests: patch api.routers.csv_routes.build_preview to raise).
Call previewCsv("p.csv", content) from the frontend, or upload the file through the UI.
Expected: the response is accepted with reason: "parse_failed" and its message.
Actual:previewCsv throws a schema error and the suggestion is silently dropped.
The fix belongs on the frontend: parse_failed is an accurate reason and comes with a readable message, so the schema should accept it (plus the optional message) rather than the API hiding it.
Fix:15268ae. csvPreviewResultSchema in csv-table-hub-main/src/lib/csv.functions.ts now accepts reason: "parse_failed" and the optional message the API sends with it. The other reasons are unchanged, and unknown reasons are still rejected.
Regression tests
Test
What it proves
csv-table-hub-main/src/__tests__/unit/preview-contract.test.ts (6 vitest cases, added in 09ff668)
Calls the real previewCsv() with a mocked fetch. parse_failed + message resolves with the message preserved; empty / header_only / no_columns still resolve; an unknown reason still throws Unexpected response shape; the request goes to /api/csv/preview
Every other invalid_structure reason the preview endpoint returns is also in the UI's enum
The tests catch the bug. Run against the pre-fix source (15268ae~1):
vitest: × accepts reason parse_failed and keeps the server message, failing with the exact error from this issue: Unexpected response shape from /api/csv/preview: reason: Invalid enum value. Expected 'empty' | 'header_only' | 'no_columns', received 'parse_failed'
pytest: FAILED test_preview_parse_failure with assert 'parse_failed' in {'empty', 'header_only', 'no_columns'}
They pass with the fix:
Local: vitest 6/6 on that file (101/101 for the frontend overall); pytest SIT-17/18 4/4.
integration (postgres service) job: executed 392 · PASSED 392 · FAILED 0 · SKIPPED 0, RESULT: PASS. Its 23 "not run" tests are only the accessibility ones, so SIT-17/18 are among the 392 that passed.
Note: the fix is on branch claude/elegant-bohr-zn28zn and reaches main when PR #41 is merged.
Activity
test: regression tests for #42 (preview parse_failed) and #43 (CORS :…
amar-python commentedon Oct 10, 2026
Fixed and verified
Fix:
15268ae.csvPreviewResultSchemaincsv-table-hub-main/src/lib/csv.functions.tsnow acceptsreason: "parse_failed"and the optionalmessagethe API sends with it. The other reasons are unchanged, and unknown reasons are still rejected.Regression tests
csv-table-hub-main/src/__tests__/unit/preview-contract.test.ts(6 vitest cases, added in09ff668)previewCsv()with a mockedfetch.parse_failed+ message resolves with the message preserved;empty/header_only/no_columnsstill resolve; an unknown reason still throwsUnexpected response shape; the request goes to/api/csv/previewtests/system_integration/test_sit_frontend_contract.py::test_preview_parse_failure(SIT-18)parse_failedplus a message, and that reason is in the UI's preview enum (read from the TS source)tests/system_integration/test_sit_frontend_contract.py::test_preview_invalid_structure(SIT-17, 3 cases)invalid_structurereason the preview endpoint returns is also in the UI's enumThe tests catch the bug. Run against the pre-fix source (
15268ae~1):× accepts reason parse_failed and keeps the server message, failing with the exact error from this issue:Unexpected response shape from /api/csv/preview: reason: Invalid enum value. Expected 'empty' | 'header_only' | 'no_columns', received 'parse_failed'FAILED test_preview_parse_failurewithassert 'parse_failed' in {'empty', 'header_only', 'no_columns'}They pass with the fix:
6f6814a(PR Group tests into unit, system, SIT, performance, accessibility and UAT #41, all 4 checks green):accessibility (playwright + axe)job, vitest step:✓ src/__tests__/unit/preview-contract.test.ts (6 tests),Tests 101 passed (101).integration (postgres service)job:executed 392 · PASSED 392 · FAILED 0 · SKIPPED 0,RESULT: PASS. Its 23 "not run" tests are only the accessibility ones, so SIT-17/18 are among the 392 that passed.Note: the fix is on branch
claude/elegant-bohr-zn28znand reachesmainwhen PR #41 is merged.Closing as fixed.
Generated by Claude Code
Merge pull request #74 from amar-python/fix/issues-42-43-on-main