fromServiceStitchObject throws on null paletteIndex, swallows success as 'Auto-digitize failed' #27

Closed
opened 2026-07-13 00:05:38 +00:00 by Mark · 2 comments
Owner

Bug — fromServiceStitchObject throws on paletteIndex: null, swallow success as "Auto-digitize failed"

Severity: P0 (silent failure of the success path).

Reproduction (after #23 and #26 are fixed):

  1. Open http://localhost:5173/workspace
  2. Upload any SVG
  3. Click the Auto-Digitize FAB (bottom-right of canvas)
  4. Service returns HTTP 200 with {stitchObjects: [...600 stitches, paletteIndex: null]} (visible in /tmp/easystitch-svc.log).
  5. UI shows the persistent red toast "Auto-digitize failed. Please try again." and the canvas stays empty.

Root cause — src/lib/digitize-adapters.ts:123-127 (pre-fix):

if (obj.paletteIndex === null || obj.paletteIndex === undefined) {
  throw new Error("service returned null paletteIndex for brother-pr10 profile");
}

The engine currently returns paletteIndex: null because the Brother PR10 catalog lookup is a downstream concern (issue #24, not implemented yet). The frontend throws in the success mapping, which the try/catch in useWorkspace.runAutoDigitize swallows as a generic error, surfacing the toast.

Fix (applied in commit pending): treat null as "unresolved", fall back to paletteIndex: 0, key colorId by the engine-supplied threadColor instead of palette-${index} (which produced palette-null).

Verification: after the fix, the live browser run produced no error toast, canvas rendered pixel content, and the service log shows POST /v1/digitize HTTP/1.1" 200 OK. Unit test added: "tolerates a null paletteIndex from the engine (falls back to 0)" — 198 / 198 unit tests still pass.

Related: discovery context is #23 (multipart fix), #26 (maxColors fix), #24 (catalog lookup, the eventual reason paletteIndex: null becomes resolvable).

## Bug — `fromServiceStitchObject` throws on `paletteIndex: null`, swallow success as "Auto-digitize failed" **Severity**: P0 (silent failure of the success path). **Reproduction** (after #23 and #26 are fixed): 1. Open http://localhost:5173/workspace 2. Upload any SVG 3. Click the Auto-Digitize FAB (bottom-right of canvas) 4. Service returns HTTP 200 with `{stitchObjects: [...600 stitches, paletteIndex: null]}` (visible in `/tmp/easystitch-svc.log`). 5. UI shows the persistent red toast "Auto-digitize failed. Please try again." and the canvas stays empty. **Root cause** — `src/lib/digitize-adapters.ts:123-127` (pre-fix): ```ts if (obj.paletteIndex === null || obj.paletteIndex === undefined) { throw new Error("service returned null paletteIndex for brother-pr10 profile"); } ``` The engine currently returns `paletteIndex: null` because the Brother PR10 catalog lookup is a downstream concern (issue #24, not implemented yet). The frontend throws in the success mapping, which the try/catch in `useWorkspace.runAutoDigitize` swallows as a generic error, surfacing the toast. **Fix** (applied in commit pending): treat null as "unresolved", fall back to `paletteIndex: 0`, key `colorId` by the engine-supplied `threadColor` instead of `palette-${index}` (which produced `palette-null`). **Verification**: after the fix, the live browser run produced no error toast, canvas rendered pixel content, and the service log shows `POST /v1/digitize HTTP/1.1" 200 OK`. Unit test added: "tolerates a null paletteIndex from the engine (falls back to 0)" — 198 / 198 unit tests still pass. **Related**: discovery context is #23 (multipart fix), #26 (maxColors fix), #24 (catalog lookup, the eventual reason `paletteIndex: null` becomes resolvable).
Author
Owner

Auto-triage: needs decompose

Marked triage-approved + needs-decompose. decompose-executor will pick this up and break it into implementable sub-issues.

## Auto-triage: needs decompose Marked `triage-approved` + `needs-decompose`. decompose-executor will pick this up and break it into implementable sub-issues.
Author
Owner

Closed: fixed in 774e0c0 (now pushed to origin/main).

fromServiceStitchObject no longer throws on paletteIndex: null. Falls back to paletteIndex: 0 and keys colorId by the engine-supplied threadColor. End-to-end browser verification:

  • Service returns 200 with 600 stitches (engine parses SVG, emits tatami fill)
  • UI shows upload success toast, no error toast, no 422 (was: persistent "Auto-digitize failed")
  • Canvas renders pixel content
  • 198 / 198 unit tests pass (one new test: "tolerates a null paletteIndex from the engine")

The reason this isn't a no-op: until #24 lands (catalog lookup), paletteIndex: null will keep being the engine's output, so this adapter fix is required for any digitize at all to round-trip cleanly.

**Closed: fixed in `774e0c0` (now pushed to origin/main).** `fromServiceStitchObject` no longer throws on `paletteIndex: null`. Falls back to `paletteIndex: 0` and keys `colorId` by the engine-supplied `threadColor`. End-to-end browser verification: - Service returns 200 with 600 stitches (engine parses SVG, emits tatami fill) - UI shows upload success toast, **no error toast, no 422** (was: persistent "Auto-digitize failed") - Canvas renders pixel content - 198 / 198 unit tests pass (one new test: "tolerates a null paletteIndex from the engine") The reason this isn't a no-op: until #24 lands (catalog lookup), `paletteIndex: null` will keep being the engine's output, so this adapter fix is required for any digitize at all to round-trip cleanly.
Mark closed this issue 2026-07-13 01:43:29 +00:00
Sign in to join this conversation.
No description provided.