gatsbyjs/gatsby · error · Error
Gatsby can't differentiate between themes ${matchingThemes.m
Error message
Gatsby can't differentiate between themes ${matchingThemes.map(theme => theme.themeName).join(` and `)} for path ${filepath} What it means
Theme component shadowing matches a file path against each theme's `src/` directory. After de-duplicating, if two distinct themes both claim the path (their `src` prefixes both match), Gatsby cannot decide which theme owns the shadowed component and aborts.
Source
Thrown at packages/gatsby/src/internal-plugins/webpack-theme-component-shadowing/index.js:253
}
return null
}
getThemeAndComponent(filepath) {
// find out which theme's src/components dir we're requiring from
const allMatchingThemes = this.themes.filter(({ themeDir }) =>
filepath.startsWith(path.join(themeDir, `src`))
)
// The same theme can be included twice in the themes list causing multiple
// matches. This case should only be counted as a single match for that theme.
const matchingThemes = _.uniqBy(allMatchingThemes, `themeName`)
// 0 matching themes happens a lot for paths we don't want to handle
// > 1 matching theme means we have a path like
// `gatsby-theme-blog/src/components/gatsby-theme-something/src/components`
if (matchingThemes.length > 1) {
throw new Error(
`Gatsby can't differentiate between themes ${matchingThemes
.map(theme => theme.themeName)
.join(` and `)} for path ${filepath}`
)
}
if (matchingThemes.length === 0) {
return [null, null]
}
const theme = matchingThemes[0]
// get the location of the component relative to its theme's src/
const [, component] = filepath.split(path.join(theme.themeDir, `src`))
return [theme, component]
}
View on GitHub (pinned to 8b06340921)
Solutions
- Rename the inner theme's package/`themeDir` so its `src` path is not a prefix collision with the outer theme.
- Move the shadowed component out of the colliding path.
- Avoid having one theme shadow another theme inside a directory whose name equals the outer theme's `src` tree.
Defensive patterns
Strategy: validation
Validate before calling
// For theme authors: assert no two theme dirs share a prefix collision.
function assertNoShadowCollision(themes) {
const dirs = themes.map(t => path.join(t.themeDir, "src"))
for (let i = 0; i < dirs.length; i++) {
for (let j = i + 1; j < dirs.length; j++) {
if (dirs[i].startsWith(dirs[j]) || dirs[j].startsWith(dirs[i])) {
throw new Error(`Theme dirs collide: ${dirs[i]} <-> ${dirs[j]}`)
}
}
}
}
Prevention
- Give each theme a unique package name and `themeDir` so `src` prefixes never nest.
- Avoid shadowing one theme's component from inside another theme's `src` tree.
- Test shadowing in a fixture site that mounts both themes together.
When it happens
Trigger: A path such as `gatsby-theme-blog/src/components/gatsby-theme-something/src/...` where one theme's directory prefix is nested inside another theme's prefix, yielding two unique matches.
Common situations: A theme that itself depends on another theme and re-exports components under a path that starts with the outer theme's `src`; renamed/duplicated theme packages sharing a `themeDir` prefix.
Related errors
- Neither "cache" or "getCache" was passed. getCache must be f
- createNodeId must be a function, was ${typeof createNodeId}
- createNode must be a function, was ${typeof createNode}
- Neither "cache" or "getCache" was passed. getCache must be f
- Plugin "${plugin.resolve}" has an "option" key in the config
AI-assisted analysis of gatsbyjs/gatsby@8b06340921 (2026-08-13).
Data as JSON: /api/errors/69b722a8bd880dba.
Report an issue: GitHub.