You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
SPFx 1.24 RC: on modern list pages an extension's hooks sometimes run against the list view host's React ("Cannot read properties of null (reading 'useContext')") #11068
An application customizer (a footer rendered into PlaceholderName.Bottom) and list view command sets, all on React 18.3.1 as the framework's externals (react, react-dom), sometimes fail on modern list and library pages. In those cases a component's first hook throws:
TypeError: Cannot read properties of null (reading 'useContext')
at b.useContext (https://res.public.onecdn.static.microsoft/files/sp-client/listview-host-assembly_1_nb-no_a4637af26e6668c1a61467340d1f7ddc.js:2:5541)
at sn (https://public-cdn.sharepointonline.com/<tenant>.sharepoint.com/sites/appcatalog/ClientSideAssets/<id>/footer-application-customizer_<hash>.js:43:41896)
at https://public-cdn.sharepointonline.com/<tenant>.sharepoint.com/sites/appcatalog/ClientSideAssets/<id>/footer-application-customizer_<hash>.js:43:627820
at N2 (https://public-cdn.sharepointonline.com/<tenant>.sharepoint.com/sites/appcatalog/ClientSideAssets/<id>/footer-application-customizer_<hash>.js:43:629976)
at fn (https://res.public.onecdn.static.microsoft/files/sp-client/react-dom-18-bundle_none_f300932fc4ce98358599.js:4:58405)
at i (https://res.public.onecdn.static.microsoft/files/sp-client/react-dom-18-bundle_none_f300932fc4ce98358599.js:4:119247)
...
The component renders through the framework's react-dom-18-bundle, but useContext resolves to the React copy inside listview-host-assembly. That copy's dispatcher is null while react-dom-18-bundle renders, so the hook throws: two copies of React on one page.
The failure is intermittent. The same page and the same packages load correctly on most attempts, and fail on some, in a test suite that opens list views with a footer and command sets (document library, a custom list). On canvas pages and single web part app pages we have not seen it.
Steps to reproduce
Make an SPFx 1.24.0-rc.0 application customizer whose component uses a hook (useContext, useState), rendered with createRoot from react-dom/client into a bottom placeholder.
Deploy it tenant-wide, or to a site, and open a modern list view or document library page on that site.
Reload the page several times. On some loads the footer fails with the error above, and the stack shows listview-host-assembly for the hook and react-dom-18-bundle for the render.
Expected behavior
The react external of an SPFx component resolves to the same React instance that the framework's react-dom uses, on list pages as on other pages, so hooks work on every load.
Reactions are currently unavailable
Activity
m365-agent-toolkit-assistant commented on Oct 20, 2026
Thank you for reporting this issue. Here is an AI-generated initial response:
Classification: Bug — the reported intermittent hook failure is inconsistent with supported React-based SPFx extensions, though the cause is not confirmed.
The stack trace appears consistent withuseContext resolving from a different React instance than the one used by the renderer. The reporter observes this on list and library pages, not canvas pages.
Thank you for reporting this issue. Here is an AI-generated initial response:
Classification: Bug — the reported intermittent hook failure is inconsistent with supported React-based SPFx extensions, though the cause is not confirmed.
The stack trace appears consistent withuseContext resolving from a different React instance than the one used by the renderer. The reporter observes this on list and library pages, not canvas pages.
What the bundle holds of the react package: only react/cjs/react-jsx-runtime. It takes React's internals from the external react.
What it does not hold: React's core (useContext, resolveDispatcher) and react-dom (createRoot).
Where the failing call was: the useContext in the trace is in listview-host-assembly, not in our bundle. On that load, the module react resolved to the list view host's copy.
Bundle configuration:
SPFx 1.24.0-rc.0 with Heft and the SPFx rig.
React 18.3.1 and react-dom 18.3.1.
config/config.json has "externals": {}.
Our one webpack change removes our own workspace packages (pp365-*) from externals, so they are bundled. It leaves react and react-dom external.
The hook error still occurs, on document libraries.
A bug on our side, fixed. Our footer customizer subscribed to navigatedEvent only at the end of an asynchronous onInit. On list pages it usually missed the first event and rendered nothing. It now also renders at the end of onInit and on placeholderProvider.changedEvent.
On a list view on the hub: we then loaded a modern list view 28 times, each in a new tab of a signed-in browser. The hook error did not occur.
On a project's document library, it did. Our end-to-end run of 2026-10-21 opens our list view command set's dialog in a document library, right after the packages are deployed. The hook error occurred on 4 of 6 attempts.
The trace is the same as before: TypeError: Cannot read properties of null (reading 'useContext') at b.useContext (listview-host-assembly_1_nb-no_a4637af26e6668c1a61467340d1f7ddc.js:2:5541).
When it occurs, the dialog does not render.
Next. We can send the traces of a failing and a passing load from that run, and a minimal extension, if that helps.
A related observation. On 7 of the 28 loads the footer still did not render, and nothing was logged as an error.
On the loads where the footer did not render: the Bottom placeholder element ([data-sp-placeholder="Bottom"]) was in the DOM, and our bundle was loaded. But the page never logged Defined clientSidePlaceholders: DialogContainer,Top,TopContent,Bottom, and changedEvent never fired. Two such loads were traced with console logging.
On the loads where it rendered: that line was logged shortly before or after our bundle arrived. Three such loads were traced with console logging.
We tested a minimal SPFx 1.24.0-rc.0 solution using React 18.3.1 as an external, with createRoot and hook-based components in both a Bottom-placeholder application customizer and a ListView Command Set dialog. We have not reproduced the exception in our test environment so far; both extension paths render successfully.
This does not rule out the reported intermittent issue. Could you share the minimal extension and the sanitized passing/failing traces you offered, including the deployment-to-dialog test sequence and loaded framework script URLs? Please also confirm whether the command-set failure occurs during manual Edge testing or primarily in the Playwright run.
We suggest tracking the missing-placeholder notification separately and cross-linking it, since that symptom can prevent rendering before React hooks execute.
7. We tested a minimal SPFx 1.24.0-rc.0 solution using React 18.3.1 as an external, with createRoot and hook-based components in both a Bottom-placeholder application customizer and a ListView Command Set dialog. We have not reproduced the exception in our test environment so far; both extension paths render successfully.
This does not rule out the reported intermittent issue. Could you share the minimal extension and the sanitized passing/failing traces you offered, including the deployment-to-dialog test sequence and loaded framework script URLs? Please also confirm whether the command-set failure occurs during manual Edge testing or primarily in the Playwright run.
We suggest tracking the missing-placeholder notification separately and cross-linking it, since that symptom can prevent rendering before React hooks execute.
Thanks for testing it. We have now reproduced it outside CI and traced it. The cause looks to be in how SharePoint's list view host registers SPFx's React module, not in the extensions.
Summary
With a cold browser cache, listview-host-assembly often runs twice on a list view. Each run registers SPFx's React module (0d910c1c-13b9-4e1c-9aa4-b008c5e42d7d_18.3.1).
When react-dom-18-bundle registers between the two registrations, react-dom and our extensions hold different React instances. The extensions' first hook then throws Cannot read properties of null (reading 'useContext').
How often it happens
Each load below was the project's document library opened in a fresh browser context, the way a first visit or an InPrivate window loads it, unless the table says otherwise.
Browser
Cache
What we did
Loads
Hook error
Chromium (Playwright 1.63)
cold
opened the command set's dialog
10
7
Microsoft Edge 141.0.3537.57 (Playwright, channel: 'msedge')
cold
opened the command set's dialog
6
3
Chromium
cold
application customizer only
8
7
Chromium
warm: one profile, consecutive tabs
opened the command set's dialog
8
1 (the 3rd load)
Chromium
cold
a custom list on the hub site, application customizer only
6
1
In the warm run, loads 5 to 8 bootstrapped through sp-loader-assembly instead, and passed.
When it happens, both of our extensions on the page throw:
the application customizer, which renders into PlaceholderName.Bottom;
the ListView command set, whose dialog never renders.
The trace
The page's own <script> loads listview-host-assembly. On the loads that fail, it is fetched a second time, by script, with this initiator (from the DevTools protocol's Network.requestWillBeSent):
n @ plt.odsp-common.js:31 < r @ plt.odsp-common.js:31 < (anonymous) @ splistwebpack.js:2
Each run registers SPFx's React module. We logged every named define with a wrapper installed before the page's scripts. Every registration of 0d910c1c-13b9-4e1c-9aa4-b008c5e42d7d_18.3.1 came from:
V.ensure listview-host-assembly_1_nb-no_a4637af26e6668c1a61467340d1f7ddc.js:131:8742
new K listview-host-assembly_1_nb-no_a4637af26e6668c1a61467340d1f7ddc.js:131:5000
ai.start listview-host-assembly_1_nb-no_a4637af26e6668c1a61467340d1f7ddc.js:143:5730
The RequireJS map (2.3.8) sends everyone to that id.
Our components map react to 0d910c1c-…_18.3.1, react-dom to aa0a46ec-1505-43cd-a44a-93f3a5aa460a_18.3.1 and react-dom/client to 3cadd7f5-5449-49c4-a153-1beb8facd90a_18.3.1.
aa0a46ec-… maps react to the same 0d910c1c-… id.
The React id has no paths entry: only the list view host defines it.
The order decides it. Two loads, in milliseconds from navigation:
All 15 where react-dom-18-bundle registered between the two React registrations threw.
None of the 15 with one registration, or both before react-dom, threw.
The exception. The hook resolves to the list view host's React while react-dom renders:
TypeError: Cannot read properties of null (reading 'useContext')
at b.useContext (listview-host-assembly_1_nb-no_a4637af26e6668c1a61467340d1f7ddc.js:2:5541)
at sn (footer-application-customizer_<hash>.js:43:41896)
...
at fn (react-dom-18-bundle_none_f300932fc4ce98358599.js:4:58405)
The command set's stack is the same, with template-selector-command-set_<hash>.js:43:10786 in place of the footer.
Framework scripts loaded
https://res.public.onecdn.static.microsoft/files/sp-client/listview-host-assembly_1_nb-no_a4637af26e6668c1a61467340d1f7ddc.js: fetched twice on failing loads, as above.
https://res.public.onecdn.static.microsoft/files/sp-client/odsp.react-18/odsp.react.lib-45e66721.js: the list view's own React. It is not the instance registered under the SPFx id.
splistwebpack build odsp-web-prod_2026-10-09.006: plt.odsp-common.js, plt.items-view.js and the others.
Our bundles: https://public-cdn.sharepointonline.com/<tenant>.sharepoint.com/sites/appcatalog/ClientSideAssets/<solution id>/footer-application-customizer_<hash>.js and …/template-selector-command-set_<hash>.js.
Both are requested by _configurePathResource in listview-host-assembly (line 130), together with the two react-dom bundles.
Manual Edge testing or Playwright?
Manual use: we have not seen it. Our manual testing runs with a warm cache, where it is rare (see the table).
Playwright: the runs use fresh browser contexts. With real Edge 141 it failed on 3 of 6 cold loads.
The deployment-to-dialog sequence
Not tied to a deployment. The loads above ran hours after the last deployment.
The CI sequence:
The .sppkg files are added to the tenant app catalog, and the sites are upgraded.
Each Playwright test opens the document library in a fresh browser context.
The test clicks the command in the command bar and waits for the dialog.
Why CI meets it more often: the fresh contexts.
To see it yourselves
Open a document library with any hook-based extension in a cold profile, with this script installed before the page's scripts. It is a Playwright addInitScript, or DevTools with "Pause on first statement" in a fresh InPrivate window:
A failing load logs the React id, then aa0a46ec-…, then the React id again.
Minimal extension
Given the trace, we would expect your minimal extension to reproduce it too, on a document library with a cold cache. If it still does not, we are happy to package ours.
The missing placeholder
As suggested, it now has an issue of its own: #11070, cross-linked here. In short:
It happens on its own: on a warm load where the list view host ran once, and nothing threw, the page never logged Defined clientSidePlaceholders and changedEvent never fired.
The double run triggers it too: none of the 8 recorded loads where the host ran twice logged that line.
Activity
m365-agent-toolkit-assistant commentedon Oct 20, 2026
👋 Hi Remi Blom-Ohlsen (@Remi749),
Thank you for reporting this issue. Here is an AI-generated initial response:
Classification: Bug — the reported intermittent hook failure is inconsistent with supported React-based SPFx extensions, though the cause is not confirmed.
useContextresolving from a different React instance than the one used by the renderer. The reporter observes this on list and library pages, not canvas pages.Upgrade check:
1.24.0-rc.0is the latest preview listed in those notes; no fixing version is documented.What to do now:
Useful links:
Remi749 commentedon Oct 21, 2026
Regarding the two requests:
No second copy of React in our bundle. The application customizer's AMD header lists
react,react-domandreact-dom/clientas externals:reactpackage: onlyreact/cjs/react-jsx-runtime. It takes React's internals from the externalreact.useContext,resolveDispatcher) andreact-dom(createRoot).useContextin the trace is inlistview-host-assembly, not in our bundle. On that load, the modulereactresolved to the list view host's copy.Bundle configuration:
config/config.jsonhas"externals": {}.pp365-*) fromexternals, so they are bundled. It leavesreactandreact-domexternal.The hook error still occurs, on document libraries.
navigatedEventonly at the end of an asynchronousonInit. On list pages it usually missed the first event and rendered nothing. It now also renders at the end ofonInitand onplaceholderProvider.changedEvent.TypeError: Cannot read properties of null (reading 'useContext') at b.useContext (listview-host-assembly_1_nb-no_a4637af26e6668c1a61467340d1f7ddc.js:2:5541).A related observation. On 7 of the 28 loads the footer still did not render, and nothing was logged as an error.
Bottomplaceholder element ([data-sp-placeholder="Bottom"]) was in the DOM, and our bundle was loaded. But the page never loggedDefined clientSidePlaceholders: DialogContainer,Top,TopContent,Bottom, andchangedEventnever fired. Two such loads were traced with console logging.Should we open a separate issue for that?
Ashlesha-MSFT commentedon Oct 21, 2026
We tested a minimal SPFx 1.24.0-rc.0 solution using React 18.3.1 as an external, with createRoot and hook-based components in both a Bottom-placeholder application customizer and a ListView Command Set dialog. We have not reproduced the exception in our test environment so far; both extension paths render successfully.
This does not rule out the reported intermittent issue. Could you share the minimal extension and the sanitized passing/failing traces you offered, including the deployment-to-dialog test sequence and loaded framework script URLs? Please also confirm whether the command-set failure occurs during manual Edge testing or primarily in the Playwright run.
We suggest tracking the missing-placeholder notification separately and cross-linking it, since that symptom can prevent rendering before React hooks execute.
Remi749 commentedon Oct 21, 2026
Thanks for testing it. We have now reproduced it outside CI and traced it. The cause looks to be in how SharePoint's list view host registers SPFx's React module, not in the extensions.
Summary
With a cold browser cache,
listview-host-assemblyoften runs twice on a list view. Each run registers SPFx's React module (0d910c1c-13b9-4e1c-9aa4-b008c5e42d7d_18.3.1).When
react-dom-18-bundleregisters between the two registrations, react-dom and our extensions hold different React instances. The extensions' first hook then throwsCannot read properties of null (reading 'useContext').How often it happens
Each load below was the project's document library opened in a fresh browser context, the way a first visit or an InPrivate window loads it, unless the table says otherwise.
channel: 'msedge')In the warm run, loads 5 to 8 bootstrapped through
sp-loader-assemblyinstead, and passed.When it happens, both of our extensions on the page throw:
PlaceholderName.Bottom;The trace
The page's own
<script>loadslistview-host-assembly. On the loads that fail, it is fetched a second time, by script, with this initiator (from the DevTools protocol'sNetwork.requestWillBeSent):Each run registers SPFx's React module. We logged every named
definewith a wrapper installed before the page's scripts. Every registration of0d910c1c-13b9-4e1c-9aa4-b008c5e42d7d_18.3.1came from:The RequireJS map (2.3.8) sends everyone to that id.
reactto0d910c1c-…_18.3.1,react-domtoaa0a46ec-1505-43cd-a44a-93f3a5aa460a_18.3.1andreact-dom/clientto3cadd7f5-5449-49c4-a153-1beb8facd90a_18.3.1.aa0a46ec-…mapsreactto the same0d910c1c-…id.pathsentry: only the list view host defines it.The order decides it. Two loads, in milliseconds from navigation:
We recorded the order on 30 loads:
react-dom-18-bundleregistered between the two React registrations threw.react-dom, threw.The exception. The hook resolves to the list view host's React while react-dom renders:
The command set's stack is the same, with
template-selector-command-set_<hash>.js:43:10786in place of the footer.Framework scripts loaded
https://res.public.onecdn.static.microsoft/files/sp-client/listview-host-assembly_1_nb-no_a4637af26e6668c1a61467340d1f7ddc.js: fetched twice on failing loads, as above.https://res.public.onecdn.static.microsoft/files/sp-client/react-dom-18-bundle_none_f300932fc4ce98358599.jshttps://res.public.onecdn.static.microsoft/files/sp-client/react-dom-client-18-bundle_none_67888f69ed394db31937.jshttps://res.public.onecdn.static.microsoft/files/sp-client/odsp.react-18/odsp.react.lib-45e66721.js: the list view's own React. It is not the instance registered under the SPFx id.splistwebpackbuildodsp-web-prod_2026-10-09.006:plt.odsp-common.js,plt.items-view.jsand the others.https://public-cdn.sharepointonline.com/<tenant>.sharepoint.com/sites/appcatalog/ClientSideAssets/<solution id>/footer-application-customizer_<hash>.jsand…/template-selector-command-set_<hash>.js._configurePathResourceinlistview-host-assembly(line 130), together with the two react-dom bundles.Manual Edge testing or Playwright?
The deployment-to-dialog sequence
.sppkgfiles are added to the tenant app catalog, and the sites are upgraded.To see it yourselves
Open a document library with any hook-based extension in a cold profile, with this script installed before the page's scripts. It is a Playwright
addInitScript, or DevTools with "Pause on first statement" in a fresh InPrivate window:A failing load logs the React id, then
aa0a46ec-…, then the React id again.Minimal extension
Given the trace, we would expect your minimal extension to reproduce it too, on a document library with a cold cache. If it still does not, we are happy to package ours.
The missing placeholder
As suggested, it now has an issue of its own: #11070, cross-linked here. In short:
Defined clientSidePlaceholdersandchangedEventnever fired.