shopify.sessionToken.get() crashes with “Cannot add property __, object is not extensible” in checkout UI extension (api_version 2026-07)
Summary
Calling await shopify.sessionToken.get() anywhere inside a checkout UI extension (native Preact / Polaris web-components target, purchase.thank-you.block.render) crashes the extension with:
Uncaught (in promise) ExtensionUsageError: TypeError: Cannot add property __, object is not extensible
The crash is not catchable from extension code — wrapping the call in try/catch does not catch it, so there is no application-level workaround. Confirmed on both a shopify app dev preview session and a genuinely deployed/released extension version (shopify app deploy) — identical error, identical compiled bundle hash — so this is not a dev-preview-only artifact.
Environment
- Shopify CLI:
4.8.0 - Extension
api_version:2026-07 - Extension type:
ui_extension, targetpurchase.thank-you.block.render - Node:
v26.7.0 @shopify/ui-extensions:2026.7.0preact:10.28.0(also reproduced on^10.10.xbefore pinning)@preact/signals: not installed in the final repro (removed — see “Ruled out” below); also reproduced with2.5.1installed- Capability:
network_access = true(approved via Partner Dashboard → API access → “Allow network access in checkout UI extensions”)
Minimal repro
extensions/thank-you-location/shopify.extension.toml:
api_version = "2026-07"
[[extensions]]
name = "location request"
handle = "thank-you-location"
type = "ui_extension"
[extensions.capabilities]
network_access = true
[[extensions.targeting]]
module = "./src/ThankYou.jsx"
target = "purchase.thank-you.block.render"
extensions/thank-you-location/src/ThankYou.jsx:
import { render } from 'preact';
export default async () => {
let debugMessage = "sessionToken.get() succeeded";
try {
await shopify.sessionToken.get();
} catch (err) {
debugMessage = "sessionToken.get() threw: " + (err?.message || String(err));
}
render(<DebugBanner message={debugMessage} />, document.body);
};
function DebugBanner({ message }) {
return (
<s-banner heading="debug">
<s-text>{message}</s-text>
</s-banner>
);
}
extensions/thank-you-location/package.json:
{
"name": "thank-you-location",
"version": "0.1.0",
"private": true,
"scripts": { "build": "shopify app build" },
"dependencies": {
"preact": "10.28.0",
"@shopify/ui-extensions": "2026.7.x"
}
}
Steps to reproduce
- Scaffold the extension above in a Shopify app (React Router app template), run
npm run dev(shopify app dev). - Add the block to the checkout’s Thank You page in the checkout editor and save.
- Place a test order on the dev store.
- Open the Thank You page’s browser console.
Observed: the crash below, before the debug banner ever renders. Expected: the debug banner renders with “sessionToken.get() succeeded” (or a caught rejection message, if the token legitimately fails for some environment reason).
Also reproduced by running shopify app deploy, releasing the new version (after granting network_access capability approval in the Partner Dashboard), stopping shopify app dev entirely, and placing a fresh order against the live, non-preview checkout — identical crash.
Full error
Uncaught (in promise) ExtensionUsageError: TypeError: Cannot add property __, object is not extensible
at eval (eval at _evalExtensionSource (data:text/javascript,...), <anonymous>:8:149912)
at Generator.throw (<anonymous>)
at rejected (eval at _evalExtensionSource (data:text/javascript,...), <anonymous>:8:2062)
Caused by: TypeError: Cannot add property __, object is not extensible
at In (8b5fe6a4846d3b8121cbb2fa09614bca.js:38:2831)
at Yt (8b5fe6a4846d3b8121cbb2fa09614bca.js:38:2052)
at at (8b5fe6a4846d3b8121cbb2fa09614bca.js:38:6755)
at Gt (8b5fe6a4846d3b8121cbb2fa09614bca.js:38:9735)
at eval (8b5fe6a4846d3b8121cbb2fa09614bca.js:38:11136)
at Generator.next (<anonymous>)
at l (8b5fe6a4846d3b8121cbb2fa09614bca.js:1:970)
(Function names are minified and change per build; the shape — four nested calls into the compiled extension bundle, then Generator.next/l — has been consistent across every build tested.)
What’s been ruled out
Starting from a more complete version of this extension (which also called fetch() after the token, and originally used useState/useEffect to show a loading spinner before the result), the following were each tried and each produced the identical crash signature, which is what narrowed this down to sessionToken.get() itself:
- Added
@preact/signalsas an explicit dependency (it’s part of Shopify’s own migration-guide “required trio” —preact,@preact/signals,@shopify/ui-extensions— but wasn’t in our originalpackage.json). - Flattened three structurally-different
<s-banner>subtrees (loading/error/ready, swapped viauseState) into one stable tree with only conditional children. - Pinned
preact@10.28.0+@preact/signals@2.5.1— versions confirmed by a Shopify developer community thread to fix a relateduseStatereactivity bug (different symptom: stale state, not a crash). No effect here. - Eliminated all conditional mounting via
<s-box display=.../>toggles instead of{cond && <X/>}, so no<s-*>element ever mounts/unmounts after the first paint. - Eliminated
useState/useEffectentirely — did the async work before the one and onlyrender()call, so Preact never performs a second render/diff pass at all. Still crashed, and the stack showed the crash now happens beforerender()is ever called. - Removed
import '@shopify/ui-extensions/preact'(whose only effect, per its source, is the module-load side effectshopify.setSignals(Signal), wiring Shopify’s reactive host data into@preact/signals) — component used no signals-based reactivity at that point, so this was untested-but-plausible dead code. No effect on the crash. - Stripped the extension to nothing but
shopify.sessionToken.get()in atry/catch(the repro above). Still crashes, uncatchably. - Ruled out dev-preview as a factor by deploying and releasing a real, published version and testing against a live, non-preview checkout. Identical crash, identical compiled bundle hash as the dev-preview test.
Impact
sessionToken.get() is documented as the canonical way to authenticate a checkout-extension → app-backend request (see Session Token API). With it uncatchably crashing the extension, there is no way for a checkout UI extension on this API version to make an authenticated fetch() call to its own backend — a core, common use case.