Skip to content

fix(js-sdk): preserve code and type from API error responses - #16769

Open
robindelaater wants to merge 1 commit into
medusajs:developfrom
robindelaater:fix/js-sdk-preserve-error-code
Open

fix(js-sdk): preserve code and type from API error responses#16769
robindelaater wants to merge 1 commit into
medusajs:developfrom
robindelaater:fix/js-sdk-preserve-error-code

Conversation

@robindelaater

@robindelaater robindelaater commented Sep 9, 2026

Copy link
Copy Markdown

Summary

Fixes #16770

What — What changes are introduced in this PR?

FetchError now exposes the code and type that the API returned alongside the message, and
normalizeResponse reads them from the error body it already parses. Includes a unit test and a
changeset.

Why — Why are these changes relevant or necessary?

The Store and Admin APIs return errors as { code, type, message }, but normalizeResponse typed
the parsed body as { message?: string } and passed only the message to FetchError. The code and
type were dropped before a consumer could read them.

This left storefronts matching on the English message string to tell one failure from another, which
breaks localization and breaks silently when a message is reworded. The most common case is
insufficient_inventory on add-to-cart or a quantity increase, where a shopper should be told the
item is out of stock rather than "something went wrong".

How — How have these changes been implemented?

  • Widened the type assertion on the parsed error body to include code and type.
  • Added code and type fields to FetchError, passed as two new constructor parameters.

Both parameters are optional and appended last, so every existing call site keeps working and no
public signature changes shape. This is additive only, nothing currently reads these fields.

Testing — How have these changes been tested, or how can the reviewer test the feature?

Added should preserve the code and type returned in the error body to
packages/core/js-sdk/src/__tests__/client.spec.ts, with an msw handler returning a realistic Medusa
error body.

Verified the test actually covers the bug by reverting only client.ts and re-running:

✕ should preserve the code and type returned in the error body
  ● Client › GET requests › should preserve the code and type returned in the error body
    Expected: "insufficient_inventory"
    Received: undefined

With the fix in place the full js-sdk suite passes: 4 suites, 33 tests, no regressions.

Also reproduced end to end against a local Medusa backend before and after the change, using a
variant with 5 in stock and requesting 999.


Examples

Before this PR the code is unavailable, so the only way to identify a failure is to match the English
message:

try {
  await sdk.store.cart.updateLineItem(cartId, itemId, { quantity: 999 })
} catch (e) {
  e.status  // 400
  e.message // "Some variant does not have the required inventory"
  e.code    // undefined
  e.type    // undefined
}

After, a consumer can branch on a stable identifier and map it to its own copy:

import { FetchError } from "@medusajs/js-sdk"

const MESSAGES: Record<string, string> = {
  insufficient_inventory: "Er is niet genoeg voorraad van dit product.",
}

try {
  await sdk.store.cart.updateLineItem(cartId, itemId, { quantity: 999 })
} catch (e) {
  if (e instanceof FetchError && e.code) {
    showToast(MESSAGES[e.code] ?? "Er ging iets mis. Probeer het opnieuw.")
  }
}

Checklist

Please ensure the following before requesting a review:

  • I have added a changeset for this PR
    • Every non-breaking change should be marked as a patch
    • To add a changeset, run yarn changeset and follow the prompts
  • The changes are covered by relevant tests
  • I have verified the code works as intended locally
  • I have linked the related issue(s) if applicable

Additional Context

The throw site is unchanged since the v2 launch, I verified the same behaviour in @medusajs/js-sdk
2.0.0, 2.5.0, 2.10.0, 2.15.0 and 2.20.1.

I limited the change to code and type because those are the two fields the API returns consistently.
If you would rather keep the whole parsed body on the error, that is an easy change happy to follow whichever you prefer.

For context on the impact: the official Next.js starter cannot surface these errors well today
either. Its medusaError helper (src/lib/util/medusa-error.ts) branches on error.response and
error.request, which are Axios properties. FetchError is fetch-based and has neither, so every
error falls through to the final branch and a shopper sees:

Error setting up the request: Some variant does not have the required inventory

That is a separate issue in the starter repo, but a code on FetchError would give it a clean way
to fix it.

The Store and Admin APIs return errors as `{ code, type, message }`, but
`normalizeResponse` typed the parsed body as `{ message?: string }` and passed
only the message to `FetchError`. The `code` and `type` were dropped before a
consumer could read them.

This left storefronts matching on the English message string to tell one
failure from another, which breaks localization and breaks silently when a
message is reworded. The most common case is `insufficient_inventory` on
add-to-cart or a quantity increase.

`FetchError` now carries `code` and `type`. Both constructor parameters are
optional and appended last, so existing call sites are unaffected.
@changeset-bot

changeset-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3b98b19

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 83 packages
Name Type
@medusajs/js-sdk Patch
@medusajs/draft-order Patch
@medusajs/dashboard Patch
@medusajs/medusa Patch
@medusajs/loyalty-plugin Patch
@medusajs/admin-bundler Patch
@medusajs/test-utils Patch
@medusajs/medusa-oas-cli Patch
integration-tests-http Patch
@medusajs/analytics Patch
@medusajs/api-key Patch
@medusajs/auth Patch
@medusajs/caching Patch
@medusajs/cart Patch
@medusajs/currency Patch
@medusajs/customer Patch
@medusajs/file Patch
@medusajs/fulfillment Patch
@medusajs/index Patch
@medusajs/inventory Patch
@medusajs/link-modules Patch
@medusajs/locking Patch
@medusajs/notification Patch
@medusajs/order Patch
@medusajs/payment Patch
@medusajs/pricing Patch
@medusajs/product Patch
@medusajs/promotion Patch
@medusajs/rbac Patch
@medusajs/region Patch
@medusajs/sales-channel Patch
@medusajs/search Patch
@medusajs/settings Patch
@medusajs/stock-location Patch
@medusajs/store Patch
@medusajs/tax Patch
@medusajs/translation Patch
@medusajs/user Patch
@medusajs/workflow-engine-inmemory Patch
@medusajs/workflow-engine-redis Patch
@medusajs/search-postgres Patch
@medusajs/oas-github-ci Patch
@medusajs/cache-inmemory Patch
@medusajs/cache-redis Patch
@medusajs/event-bus-local Patch
@medusajs/event-bus-redis Patch
@medusajs/analytics-local Patch
@medusajs/analytics-posthog Patch
@medusajs/auth-emailpass Patch
@medusajs/auth-github Patch
@medusajs/auth-google Patch
@medusajs/auth-oidc Patch
@medusajs/caching-redis Patch
@medusajs/file-local Patch
@medusajs/file-s3 Patch
@medusajs/fulfillment-manual Patch
@medusajs/locking-postgres Patch
@medusajs/locking-redis Patch
@medusajs/notification-local Patch
@medusajs/notification-sendgrid Patch
@medusajs/payment-stripe Patch
@medusajs/core-flows Patch
@medusajs/framework Patch
@medusajs/instantsearch-adapter Patch
@medusajs/modules-sdk Patch
@medusajs/orchestration Patch
@medusajs/query Patch
@medusajs/types Patch
@medusajs/utils Patch
@medusajs/workflows-sdk Patch
create-medusa-app Patch
@medusajs/http-types-generator Patch
@medusajs/cli Patch
@medusajs/deps Patch
@medusajs/eslint-plugin Patch
@medusajs/telemetry Patch
@medusajs/admin-sdk Patch
@medusajs/admin-shared Patch
@medusajs/admin-vite-plugin Patch
@medusajs/icons Patch
@medusajs/toolbox Patch
@medusajs/ui-preset Patch
@medusajs/ui Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@robindelaater
robindelaater marked this pull request as ready for review September 9, 2026 10:17
@robindelaater
robindelaater requested a review from a team as a code owner September 9, 2026 10:17
@medusa-os-bot

medusa-os-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown

Thanks for the contribution! We need more information before reviewing this further.

The PR adds code and type properties to FetchError so that JS SDK consumers can branch on stable API error identifiers rather than matching on English message strings. The implementation is additive and backward-compatible: two new optional constructor parameters are appended last, normalizeResponse widens its type assertion to include them, and the existing call site passes them through. A unit test is included using an msw handler that returns a realistic Medusa error body, and the test was verified to fail against a revert of client.ts. The changeset is present with the correct patch bump and fix(js-sdk): ... message format. The only issue blocking initial approval is a missing linked issue — the contribution guidelines require one for non-trivial changes, and this fix (new public API surface on FetchError, present since v2.0.0) does not qualify as a trivial one-liner.

Triggered by: PR marked as ready for review

@medusa-os-bot

medusa-os-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown

Thanks for the contribution! Initial automated review looks good.

Re-review. The previous blocking point — a missing linked issue — has been resolved: issue #16770 is now linked via a closing keyword and is open. All other criteria are met. The implementation is additive and fully backward-compatible. Two new optional constructor parameters (code and type) are appended at the end of FetchError's constructor signature, so all existing call sites remain untouched. The normalizeResponse function widens its type assertion to include code and type, and passes them through when present in the error body. Checklist verified: - PR template is fully completed with What, Why, How, and Testing sections. - Linked issue #16770 is real, open, and describes the same problem. - Changeset present at .changeset/js-sdk-preserve-error-code.md, with correct patch bump and fix(js-sdk): … message format. - Unit test added in packages/core/js-sdk/src/tests/client.spec.ts using an msw handler that returns a realistic Medusa error body; all four assertions (status, message, code, type) are covered, and the author verified the test fails against a revert of client.ts. - No security concerns: the code and type values are stored as error properties in a client-side SDK; they do not reach any dangerous sink. - No performance concerns. - No bugs: optional fields default to undefined when absent from the response body, and the JSON parse already has a .catch(() => ({})) guard. - Conventions followed: naming, code style, and no issue/PR references in code comments.

Triggered by: PR description updated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: JS SDK drops code and type from API error responses

1 participant