gatsbyjs/gatsby · error
Failed to resolve ${themeName}
Error message
Failed to resolve ${themeName} What it means
Thrown by Gatsby's theme loader when resolving a theme that is not the main config fails locally. The loader first tries a local theme at <rootDir>/plugins/<themeName> via resolvePlugin; if that throws (the local plugin is invalid or missing required files), it immediately panics with the caught localErr attached. This is the 'local theme exists but is broken' branch, distinct from the 'cannot find theme at all' branch that follows.
Source
Thrown at packages/gatsby/src/bootstrap/load-themes/index.ts:57
const scopedRequire = createRequireFromPath(`${rootDir}/:internal:`)
// theme is an node-resolvable module
themeDir = path.dirname(scopedRequire.resolve(themeName))
} catch (e) {
let pathToLocalTheme
// only try to look for local theme in main site
// local themes nested in other themes is potential source of problems:
// because those are not hosted by npm, there is potential for multiple
// local themes with same name that do different things and name being
// main identifier that Gatsby uses right now, it's safer not to support it for now.
if (isMainConfig) {
pathToLocalTheme = path.join(rootDir, `plugins`, themeName)
// is a local plugin OR it doesn't exist
try {
const { resolve } = resolvePlugin(themeName, rootDir)
themeDir = resolve
} catch (localErr) {
reporter.panic(`Failed to resolve ${themeName}`, localErr)
}
}
if (!themeDir) {
const nodeResolutionPaths = module.paths.map(p => path.join(p, themeName))
reporter.panic({
id: `10226`,
context: {
themeName,
configFilePath: configFileThatDeclaredTheme,
pathToLocalTheme,
nodeResolutionPaths,
},
})
}
}
const { configModule, configFilePath } = await getConfigFile(View on GitHub (pinned to 8b06340921)
Solutions
- Open the localErr object printed with the panic: it carries the specific reason resolvePlugin failed.
- Verify plugins/<themeName>/ has a valid package.json (with a correct 'main' or 'name') and a gatsby-node.js or gatsby-config.js if the theme uses them.
- Run npm/yarn install inside the local theme directory to ensure its own dependencies are present.
- If the theme is meant to come from npm, remove the local plugins/<themeName> directory so node resolution applies.
Defensive patterns
Strategy: validation
Validate before calling
// Before starting Gatsby, sanity-check local themes resolve:
const path = require('path'), fs = require('fs')
for (const theme of (config.plugins || [])) {
const name = typeof theme === 'string' ? theme : theme.resolve
const local = path.join(process.cwd(), 'plugins', name)
if (fs.existsSync(local)) {
const pkg = path.join(local, 'package.json')
if (!fs.existsSync(pkg)) console.warn(`Local theme ${name} missing package.json`)
}
} Prevention
- Keep local theme directories self-contained: package.json + entry file.
- Run install inside local theme directories.
- Remove empty plugins/<name> directories when the theme is expected from npm.
- Use the localErr object printed with the panic to find the precise resolution failure.
When it happens
Trigger: A theme listed in gatsby-config.js resolves to plugins/<themeName> on disk, but resolvePlugin throws because gatsby-node.js/gatsby-config.js is missing, package.json is malformed, or the plugin does not satisfy the local plugin contract.
Common situations: Renaming a theme directory without updating gatsby-config.js; a local theme missing its index or gatsby-node entry; a local theme whose package.json 'main' points to a non-existent file; symlinking a theme whose dependencies are not installed.
Related errors
- Plugin "${plugin.resolve}" has an "option" key in the config
- Local plugin ${pluginName} requires a package.json file
- No support for arrays not at the end of path
- Gatsby can't differentiate between themes ${matchingThemes.m
- MissingInfoError
AI-assisted analysis of gatsbyjs/gatsby@8b06340921 (2026-08-13).
Data as JSON: /api/errors/144fcf5dfcbd06eb.
Report an issue: GitHub.