Summary
DataFetcher.processRegions() does not forward passAlong when it recurses into region components. As a result, custom values handed to dataFetcher.process() reach page processors but never reach the part and layout processors inside regions — they silently receive undefined.
The types say otherwise, which is what makes this expensive to debug: addPart and addLayout accept the same OVERRIDES generic as addPage, so the code typechecks cleanly and fails only at runtime.
Where
src/main/resources/lib/enonic/react4xp/DataFetcher.ts:453 (master):
private processRegions(component: PageComponent | LayoutComponent): RegionsData {
...
const processedComponent = this.doProcess({
component: origComponent, // <-- passAlong not forwarded
});
processPage and processLayout both destructure ...passAlong and correctly hand it to invokeProcessor for their own processor — but they call this.processRegions(component) without it, so the chain is cut for every descendant. invokeProcessor then injects only the built-ins (dataFetcher, component, content, request, runMode).
Reproduction
// controller
dataFetcher.process({content, request, site, mySiteConfig: getSiteConfig()});
// page processor — mySiteConfig is defined ✅
dataFetcher.addPage('com.example:default', {
processor: ({mySiteConfig}) => ({ok: !!mySiteConfig})
});
// part processor in a region — mySiteConfig is undefined ❌
dataFetcher.addPart('com.example:my-part', {
processor: ({mySiteConfig}) => ({ok: !!mySiteConfig})
});
Both typecheck. Only the page processor gets a value.
Affected versions
Present unchanged in every release that ships DataFetcher — verified by diffing the bundled lib/enonic/react4xp/index.js in the published jars for 6.0.0, 6.0.1, 6.1.0, 6.1.1 and 7.0.0. Not a regression; it has never worked.
Impact
Found in production on market.enonic.com. A part processor read searchResultPage from the site config passed along from the controller; it resolved to undefined, the front-page search form rendered with an empty action="", and the browser submitted back to the current page instead of the search results page. Because an empty action is valid HTML and undefined config degraded to '', nothing errored — the search box just quietly stopped working.
Suggested fix
Forward passAlong through the recursion:
private processRegions(component, passAlong) {
...
const processedComponent = this.doProcess({...passAlong, component: origComponent});
with the two call sites in processPage/processLayout updated to this.processRegions(component, passAlong).
If forwarding is not the intended behaviour, then the OVERRIDES generic should be removed from addPart/addLayout so the type system stops promising something the runtime does not deliver — and the limitation documented. Either way the current combination is a trap.
Summary
DataFetcher.processRegions()does not forwardpassAlongwhen it recurses into region components. As a result, custom values handed todataFetcher.process()reach page processors but never reach the part and layout processors inside regions — they silently receiveundefined.The types say otherwise, which is what makes this expensive to debug:
addPartandaddLayoutaccept the sameOVERRIDESgeneric asaddPage, so the code typechecks cleanly and fails only at runtime.Where
src/main/resources/lib/enonic/react4xp/DataFetcher.ts:453(master):processPageandprocessLayoutboth destructure...passAlongand correctly hand it toinvokeProcessorfor their own processor — but they callthis.processRegions(component)without it, so the chain is cut for every descendant.invokeProcessorthen injects only the built-ins (dataFetcher,component,content,request,runMode).Reproduction
Both typecheck. Only the page processor gets a value.
Affected versions
Present unchanged in every release that ships
DataFetcher— verified by diffing the bundledlib/enonic/react4xp/index.jsin the published jars for 6.0.0, 6.0.1, 6.1.0, 6.1.1 and 7.0.0. Not a regression; it has never worked.Impact
Found in production on market.enonic.com. A part processor read
searchResultPagefrom the site config passed along from the controller; it resolved toundefined, the front-page search form rendered with an emptyaction="", and the browser submitted back to the current page instead of the search results page. Because an emptyactionis valid HTML andundefinedconfig degraded to'', nothing errored — the search box just quietly stopped working.Suggested fix
Forward
passAlongthrough the recursion:with the two call sites in
processPage/processLayoutupdated tothis.processRegions(component, passAlong).If forwarding is not the intended behaviour, then the
OVERRIDESgeneric should be removed fromaddPart/addLayoutso the type system stops promising something the runtime does not deliver — and the limitation documented. Either way the current combination is a trap.