Service caps stitch objects at 50,000 (and the design's maxStitchCount is 200,000) but the export dialog has no client-side guard — large designs fail at export with a 422 instead of pre-flight warning #169

Closed
opened 2026-10-03 17:30:29 +00:00 by Mark · 1 comment
Owner

Finding

The service's StitchObject schema declares maxItems: 50000 for the stitchObjects array (POST /v1/export). The machine profile's limits.maxStitchCount is 200,000 (per src/lib/easystitch-client.ts:36-78, all 6 machines cap at 200k).

The Export dialog (src/components/workspace/ExportDialog.tsx) does not pre-check the design's stitch count or object count before calling exportPES. A user with a dense design that exceeds the limit:

  1. Configures format, picks PES
  2. Clicks Export
  3. The service returns 422 with a maxItems violation
  4. The dialog's useAsyncState catches the error, dispatches an error toast with the service message
  5. The user sees "Export failed: ... 50,000 maxItems" — they have to figure out the implication (this isn't a transient failure, the design is too large)

The user should see a pre-flight warning: "This design has 78,000 stitches, which exceeds the 50,000 limit. Consider reducing density or splitting the design." before they click Export.

Where

  • Service schema: POST /v1/export request body, stitchObjects field (verified at runtime via /openapi.json)
  • Machine profile limits: src/lib/easystitch-client.ts:36-78 (200,000 across all 6 machines)
  • Export dialog: src/components/workspace/ExportDialog.tsx:exportRequest (line 64-75) — no pre-flight check
  • Service response: returns 422 with extra_forbidden / maxItems violation

Suggested fix shape

Add a pre-flight check to exportRequest in ExportDialog.tsx:

  1. Compute stitch count from stitchObjects:

    const totalStitches = stitchObjects.reduce((sum, o) => sum + (o.stitchCount ?? 0), 0);
    
  2. Check against limits:

    const profile = MACHINE_PROFILES[designSettings.machineProfile];
    const objLimit = 50_000; // service's maxItems for the request body
    if (stitchObjects.length > objLimit) {
      throw new Error(`Too many objects: ${stitchObjects.length} > ${objLimit}`);
    }
    if (totalStitches > profile.limits.maxStitchCount) {
      throw new Error(`Too many stitches: ${totalStitches} > ${profile.limits.maxStitchCount}`);
    }
    
  3. Surface in the UI: in the dialog's body, near the format buttons, render:

    This design: 45,231 stitches across 12 objects (PR-1050X limit: 200,000 stitches)
    

    If the design is over the limit, render an inline warning (similar to the inlineError at line 295) and disable the Export button.

  4. Show the count from the design — the workspace already tracks stitchCount per object; the total is a sum.

Severity

Medium. Users with realistic designs hit this and get a confusing error. Pre-flight checking makes the limit visible before the user clicks Export.

Discovered by

Gap analysis (2026-10-02) of export affordances.

  • #114 (closed) — verified the export flow works. Didn't include the size cap test.
  • #136 (closed) — added machine profile definitions. The limits field is now defined; this issue consumes it.
## Finding The service's `StitchObject` schema declares `maxItems: 50000` for the `stitchObjects` array (`POST /v1/export`). The machine profile's `limits.maxStitchCount` is 200,000 (per `src/lib/easystitch-client.ts:36-78`, all 6 machines cap at 200k). The Export dialog (`src/components/workspace/ExportDialog.tsx`) does not pre-check the design's stitch count or object count before calling `exportPES`. A user with a dense design that exceeds the limit: 1. Configures format, picks PES 2. Clicks Export 3. The service returns 422 with a `maxItems` violation 4. The dialog's `useAsyncState` catches the error, dispatches an error toast with the service message 5. The user sees "Export failed: ... 50,000 maxItems" — they have to figure out the implication (this isn't a transient failure, the design is too large) The user should see a pre-flight warning: "This design has 78,000 stitches, which exceeds the 50,000 limit. Consider reducing density or splitting the design." before they click Export. ## Where - Service schema: `POST /v1/export` request body, `stitchObjects` field (verified at runtime via `/openapi.json`) - Machine profile limits: `src/lib/easystitch-client.ts:36-78` (200,000 across all 6 machines) - Export dialog: `src/components/workspace/ExportDialog.tsx:exportRequest` (line 64-75) — no pre-flight check - Service response: returns 422 with `extra_forbidden` / `maxItems` violation ## Suggested fix shape Add a pre-flight check to `exportRequest` in `ExportDialog.tsx`: 1. **Compute stitch count** from `stitchObjects`: ```ts const totalStitches = stitchObjects.reduce((sum, o) => sum + (o.stitchCount ?? 0), 0); ``` 2. **Check against limits**: ```ts const profile = MACHINE_PROFILES[designSettings.machineProfile]; const objLimit = 50_000; // service's maxItems for the request body if (stitchObjects.length > objLimit) { throw new Error(`Too many objects: ${stitchObjects.length} > ${objLimit}`); } if (totalStitches > profile.limits.maxStitchCount) { throw new Error(`Too many stitches: ${totalStitches} > ${profile.limits.maxStitchCount}`); } ``` 3. **Surface in the UI**: in the dialog's body, near the format buttons, render: ``` This design: 45,231 stitches across 12 objects (PR-1050X limit: 200,000 stitches) ``` If the design is over the limit, render an inline warning (similar to the `inlineError` at line 295) and disable the Export button. 4. **Show the count from the design** — the workspace already tracks `stitchCount` per object; the total is a sum. ## Severity Medium. Users with realistic designs hit this and get a confusing error. Pre-flight checking makes the limit visible before the user clicks Export. ## Discovered by Gap analysis (2026-10-02) of export affordances. ## Related - #114 (closed) — verified the export flow works. Didn't include the size cap test. - #136 (closed) — added machine profile definitions. The `limits` field is now defined; this issue consumes it.
Author
Owner

Fixed via 61239e2 on main. Pre-flight size guard added to ExportDialog:

  • New size summary line under the hoop confirmation showing stitch + object totals and the active machine limit (data-testid export-size-summary); goes red when over the stitch cap.
  • Export button disabled when either limit is exceeded.
  • handleExport short-circuits with the existing inline-error banner when either limit trips, with a clear remediation hint.

24/24 ExportDialog tests, 711/711 repo tests, clean tsc + eslint.

Fixed via 61239e2 on main. Pre-flight size guard added to ExportDialog: - New size summary line under the hoop confirmation showing stitch + object totals and the active machine limit (data-testid `export-size-summary`); goes red when over the stitch cap. - Export button disabled when either limit is exceeded. - handleExport short-circuits with the existing inline-error banner when either limit trips, with a clear remediation hint. 24/24 ExportDialog tests, 711/711 repo tests, clean tsc + eslint.
Mark closed this issue 2026-10-03 18:07:03 +00:00
Sign in to join this conversation.
No description provided.