Skip to content

[finding] normaliseClientError's first CONCURRENT_UPDATE guard is subsumed by the line under it — the httpStatus === 409 half decides nothing #6375

Description

@os-support-ai

Observation-class finding, spotted while reading the boundary for objectui#5902. Not touched by that PR — its dispatch scoped packages/data-objectstack out (the boundary work from objectui#5901 is done and merged), so this is recorded rather than edited.

What

packages/data-objectstack/src/index.ts, the tail of normaliseClientError:

if (e.code !== 'CONCURRENT_UPDATE' && e.httpStatus !== 409) return error;
if (e.code !== 'CONCURRENT_UPDATE') return error;
return new ConcurrentUpdateError({ ... });

The second line's condition is strictly weaker than the first's, so the first line can never be the one that decides an outcome:

code httpStatus line 1 line 2 outcome
CONCURRENT_UPDATE ≠ 409 returns would also return passthrough
CONCURRENT_UPDATE 409 falls through returns passthrough
CONCURRENT_UPDATE any falls through falls through typed error

Delete line 1 and every input keeps its current answer. The httpStatus !== 409 half in particular reads as if a bare 409 could still be re-wrapped; it cannot.

Why it is worth a card rather than a silent cleanup

It is dead code, not a behaviour bug — the effective rule is "the wire code is the discriminator", which is a reasonable rule and the one the function's own doc comment describes. What makes it worth recording is that the line advertises a second acceptance path that does not exist, on a function whose whole job is deciding which errors get re-wrapped. A reader adding a shape here has to re-derive the truth table to find out that half of the first guard is inert.

There is a related asymmetry worth deciding at the same time: the exported isConcurrentUpdateError in the same file accepts name === 'ConcurrentUpdateError' as well as the code, while normaliseClientError accepts only the code. Consumers duck-typing through the exported predicate and consumers relying on the re-wrap therefore disagree about one shape.

Severity

Low, and deliberately filed flat rather than pre-graded — no user-visible symptom, no test moves either way. Triage decides whether it is worth a patch at all or whether the right move is a one-line comment naming the code as the sole discriminator.

Where

  • packages/data-objectstack/src/index.tsnormaliseClientError, the two guards immediately before return new ConcurrentUpdateError(...)
  • packages/data-objectstack/src/index.tsisConcurrentUpdateError, for the asymmetry above

Found from: objectui#5902 (drag-write surfaces reading the producer-marked userMessage).

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions