{"record":{"id":"63a9fca9c753d68c","repo":"gatsbyjs/gatsby","slug":"plugin-plugin-resolve-has-an-option-key-in","errorCode":null,"errorMessage":"Plugin \"${plugin.resolve}\" has an \"option\" key in the configuration. Did you mean \"options\"?","messagePattern":"Plugin \"(.+?)\" has an \"option\" key in the configuration\\. Did you mean \"options\"\\?","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/gatsby/src/bootstrap/load-plugins/process-plugin.ts","lineNumber":28,"sourceCode":"  if (isString(plugin)) {\n    const info = resolvePlugin(plugin, rootDir)\n\n    return {\n      ...info,\n      pluginOptions: {\n        plugins: [],\n      },\n    }\n  }\n\n  plugin.options = plugin.options || {}\n\n  // Throw an error if there is an \"option\" key.\n  if (\n    isEmpty(plugin.options) &&\n    !isEmpty((plugin as { option?: unknown }).option)\n  ) {\n    throw new Error(\n      `Plugin \"${plugin.resolve}\" has an \"option\" key in the configuration. Did you mean \"options\"?`\n    )\n  }\n\n  // Plugins can have plugins.\n  if (plugin.subPluginPaths) {\n    for (const subPluginPath of plugin.subPluginPaths) {\n      const segments = subPluginPath.split(`.`)\n      let roots: Array<any> = [plugin.options]\n\n      let pathToSwap = segments\n\n      for (const segment of segments) {\n        if (segment === `[]`) {\n          pathToSwap = pathToSwap.slice(0, pathToSwap.length - 1)\n          roots = roots.flat()\n        } else {\n          roots = roots.map(root => root[segment])","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/gatsbyjs/gatsby/blob/8b06340921ffdf23125a365b9c9923690cb62ce6/packages/gatsby/src/bootstrap/load-plugins/process-plugin.ts#L10-L46","documentation":"Gatsby plugin config objects use an `options` (plural) key. The loader treats an empty `options` together with a present `option` (singular) as a near-certain typo and rejects it, so the intended config is never silently ignored.","triggerScenarios":"A `gatsby-config.js` entry like `{ resolve: \"gatsby-plugin-x\", option: { trackingId: \"...\" } }` (singular, and no `options`).","commonSituations":"Copy-paste from outdated docs/examples; muscle memory from libraries that use a singular `option`.","solutions":["Rename the `option` key to `options` in the plugin entry.","Confirm the plugin's README for the exact key name before re-running."],"exampleFix":"// before\n{ resolve: `gatsby-plugin-google-analytics`, option: { trackingId: `UA-1` } }\n// after\n{ resolve: `gatsby-plugin-google-analytics`, options: { trackingId: `UA-1` } }","handlingStrategy":"validation","validationCode":"// Validate gatsby-config plugin entries before booting.\nfunction validatePlugins(plugins) {\n  for (const p of plugins) {\n  if (typeof p === \"object\" && p && \"option\" in p && !(\"options\" in p)) {\n  throw new Error(`Plugin ${p.resolve} uses \"option\" — did you mean \"options\"?`)\n  }\n  }\n}\n","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Author gatsby-config with TypeScript types for plugin entries.","Run a config-validation script in pre-commit/CI.","Copy plugin options from the plugin's current README, not old blog posts."],"tags":["config","plugins","gatsby","gatsby-config"],"backgroundTag":null,"analyzedSha":"8b06340921ffdf23125a365b9c9923690cb62ce6","analyzedAt":"2026-08-13T02:36:21.405Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}