Skip to content

Frontend rejects /api/csv/preview reason "parse_failed" — T&E table suggestion silently lost #42

Closed

Description

@amar-python

Summary

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

  1. Make the server parser throw on a file (in tests: patch api.routers.csv_routes.build_preview to raise).
  2. Call previewCsv("p.csv", content) from the frontend, or upload the file through the UI.
  3. Expected: the response is accepted with reason: "parse_failed" and its message.
  4. Actual: previewCsv throws a schema error and the suggestion is silently dropped.

Notes

Activity

  1. added a commit that references this issue on Oct 10, 2026
  2. amar-python commented on Oct 10, 2026

    @amar-python
    OwnerAuthor

    Fixed and verified

    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
    tests/system_integration/test_sit_frontend_contract.py::test_preview_parse_failure (SIT-18) Live API with a simulated parser crash returns parse_failed plus 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) 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.
    • CI on 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-zn28zn and reaches main when PR #41 is merged.

    Closing as fixed.


    Generated by Claude Code

  3. added a commit that references this issue on Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions