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

  1. Open the localErr object printed with the panic: it carries the specific reason resolvePlugin failed.
  2. 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.
  3. Run npm/yarn install inside the local theme directory to ensure its own dependencies are present.
  4. 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

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


AI-assisted analysis of gatsbyjs/gatsby@8b06340921 (2026-08-13). Data as JSON: /api/errors/144fcf5dfcbd06eb. Report an issue: GitHub.