Bug: /v1/export validates stitchObjects first, never reports invalid 'format' on empty input #29

Closed
opened 2026-09-09 20:29:53 +00:00 by Mark · 1 comment
Owner

Summary

POST /v1/export with {stitchObjects: [], format: "xxx"} returns the stitchObjects-empty validation error first and never surfaces the format-not-in-enum error. The error list is incomplete — clients see only the first failure and don't know the format value is also wrong.

Reproduction

curl -s -X POST http://127.0.0.1:8080/v1/export \
  -H 'Content-Type: application/json' \
  -d '{"stitchObjects": [], "format": "xxx"}'

# Returns:
# {"detail":[
#   {"type":"too_short","loc":["body","stitchObjects"],"msg":"List should have at least 1 item after validation, not 0","input":[],"ctx":{"field_type":"List","min_length":1,"actual_length":0}},
#   {"type":"missing","loc":["body","stitchObjects"],"msg":"Field required","input":null}  # duplicated
# ]}
# → NO mention of format being invalid (xxx is not in [pes, dst, exp, jef])

Compare with non-empty but bad format:

curl -s -X POST http://127.0.0.1:8080/v1/export \
  -d '{"stitchObjects": [{"id":"x","type":"satin","threadColor":"#FF0000","stitches":[]}], "format": "xxx"}'

# Returns 200 OK with valid PES bytes — the empty stitches list gets silently accepted!

Three problems in one place

  1. Validation only reports the first failure type — clients with multiple bad fields see partial feedback
  2. The same {stitchObjects: []} produces TWO detail entries (too_short + missing) — duplication
  3. Empty stitches inside a non-empty list is silently accepted (returns 200 with bogus PES bytes)

Suggested fix

  • Configure Pydantic to accumulate all validation errors (likely already supposed to; check the FastAPI config)
  • Investigate the duplicate too_short + missing entries for empty list
  • Add a non-empty check on the stitches field inside each StitchObject (currently it's list[Point] with no min_items constraint)

Environment

  • service version: 0.1.0
  • probed 2026-09-09 via /v1/export

UI verification follow-up (2026-09-10)

The file upload barrier is now cracked (DataTransfer + Object.defineProperty + dispatchEvent). Confirmed via BrowserOS MCP snapshot that ThreadCraft's settings panel unlocks after upload but:

  • FABRIC TYPE / STABILIZER / HOOP SIZE comboboxes in the Design Settings panel render all options in the accessibility tree but clicking any option via act click / act kind=select / PointerEvent sequence closes the dropdown without updating React state. The next snapshot re-shows the original option as [selected]. Captured React props via __reactProps confirmed onClick exists but does not fire under synthetic dispatch.
  • Auto-Digitize (toolbar FAB e12 or inner-modal Confirm & Edit e65) sets Redux state to 'digitizing' then 'digitized' with a hardcoded "Auto-digitize complete!" message but never fires runAutoDigitize() → digitize() → POST to /v1/digitize. BrowserOS MCP hook fetch confirmed only /healthz GETs during the click sequence. Service log shows zero digitize POSTs across the entire 2026-09-09/10 verification session.

This means the UI cannot drive a digitize or export at all in the current ThreadCraft build. The API bugs (#27-31) are still the canonical surface; the UI bugs are symptom-level and tracked separately as #32 (silent no-op), #33 (combobox click swallowed), #34 (false-complete message). Those three will be closed as duplicates of this issue family once the canonical root causes land.

## Summary `POST /v1/export` with `{stitchObjects: [], format: "xxx"}` returns the **stitchObjects-empty** validation error first and never surfaces the **format-not-in-enum** error. The error list is incomplete — clients see only the first failure and don't know the format value is also wrong. ## Reproduction ```bash curl -s -X POST http://127.0.0.1:8080/v1/export \ -H 'Content-Type: application/json' \ -d '{"stitchObjects": [], "format": "xxx"}' # Returns: # {"detail":[ # {"type":"too_short","loc":["body","stitchObjects"],"msg":"List should have at least 1 item after validation, not 0","input":[],"ctx":{"field_type":"List","min_length":1,"actual_length":0}}, # {"type":"missing","loc":["body","stitchObjects"],"msg":"Field required","input":null} # duplicated # ]} # → NO mention of format being invalid (xxx is not in [pes, dst, exp, jef]) ``` Compare with non-empty but bad format: ```bash curl -s -X POST http://127.0.0.1:8080/v1/export \ -d '{"stitchObjects": [{"id":"x","type":"satin","threadColor":"#FF0000","stitches":[]}], "format": "xxx"}' # Returns 200 OK with valid PES bytes — the empty stitches list gets silently accepted! ``` ## Three problems in one place 1. Validation only reports the **first** failure type — clients with multiple bad fields see partial feedback 2. The same `{stitchObjects: []}` produces TWO detail entries (`too_short` + `missing`) — duplication 3. **Empty stitches inside a non-empty list** is silently accepted (returns 200 with bogus PES bytes) ## Suggested fix - Configure Pydantic to accumulate all validation errors (likely already supposed to; check the FastAPI config) - Investigate the duplicate `too_short` + `missing` entries for empty list - Add a non-empty check on the `stitches` field inside each `StitchObject` (currently it's `list[Point]` with no `min_items` constraint) ## Environment - service version: 0.1.0 - probed 2026-09-09 via /v1/export --- **UI verification follow-up (2026-09-10)** The file upload barrier is now cracked (DataTransfer + Object.defineProperty + dispatchEvent). Confirmed via BrowserOS MCP `snapshot` that ThreadCraft's settings panel unlocks after upload but: - FABRIC TYPE / STABILIZER / HOOP SIZE comboboxes in the Design Settings panel render all options in the accessibility tree but **clicking any option via `act click` / `act kind=select` / PointerEvent sequence closes the dropdown without updating React state**. The next snapshot re-shows the original option as `[selected]`. Captured React props via `__reactProps` confirmed `onClick` exists but does not fire under synthetic dispatch. - Auto-Digitize (toolbar FAB `e12` or inner-modal Confirm & Edit `e65`) sets Redux state to `'digitizing'` then `'digitized'` with a hardcoded "Auto-digitize complete!" message **but never fires `runAutoDigitize()` → `digitize()` → POST to `/v1/digitize`**. BrowserOS MCP `hook fetch` confirmed only `/healthz` GETs during the click sequence. Service log shows zero digitize POSTs across the entire 2026-09-09/10 verification session. This means **the UI cannot drive a digitize or export at all in the current ThreadCraft build**. The API bugs (#27-31) are still the canonical surface; the UI bugs are symptom-level and tracked separately as #32 (silent no-op), #33 (combobox click swallowed), #34 (false-complete message). Those three will be closed as duplicates of this issue family once the canonical root causes land.
Author
Owner

Visual verification (2026-09-09, via vision_analyze on 07_after_export_click.png): The Export Design dialog opens successfully with FILE NAME field "untitled", FORMAT options (PES/DST/SVG/PDF), and helper text "This design uses 0 Brother PR-10 thread stops" (the vision model misread "bristles" and "PF-10" — actual UI text per MCP read tool earlier was "Brother PR-10"). The UI does NOT raise a "no design to export" error visible in the dialog. No clear rejection banner visible — the user only sees the export dialog open. The API bug (accepting empty stitchObjects) is masked by this permissive UI behavior.

Visual verification (2026-09-09, via vision_analyze on `07_after_export_click.png`): The Export Design dialog opens successfully with FILE NAME field "untitled", FORMAT options (PES/DST/SVG/PDF), and helper text "This design uses 0 Brother PR-10 thread stops" (the vision model misread "bristles" and "PF-10" — actual UI text per MCP `read` tool earlier was "Brother PR-10"). **The UI does NOT raise a "no design to export" error visible in the dialog.** No clear rejection banner visible — the user only sees the export dialog open. The API bug (accepting empty stitchObjects) is masked by this permissive UI behavior.
Mark 2026-09-13 01:05:48 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Mark/easystitch-service#29
No description provided.