{"record":{"id":"c4ecccd9634e58be","repo":"gatsbyjs/gatsby","slug":"keepdynamicimports-option-needs-to-be-an-array","errorCode":null,"errorMessage":"keepDynamicImports option needs to be an array","messagePattern":"keepDynamicImports option needs to be an array","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/babel-preset-gatsby-package/lib/babel-transform-mark-to-keep-dynamic-import.js","lineNumber":30,"sourceCode":"/**\n * @typedef {Object} IPluginOptions\n * @property {Array<string>} keepDynamicImports\n */\n\n/**\n *\n * @param {{ types: BabelTypes }} _unused\n * @param {Partial<IPluginOptions>} opts\n * @returns {PluginObj}\n */\nmodule.exports = function keepDynamicImports(\n  _unused,\n  opts\n) {\n  if (!opts.keepDynamicImports) {\n    throw new Error(`keepDynamicImports option needs to be set`)\n  } else if (!Array.isArray(opts.keepDynamicImports)) {\n    throw new Error(`keepDynamicImports option needs to be an array`)\n  }\n\n  const absolutePaths = opts.keepDynamicImports.map(p => path.resolve(p))\n\n  return {\n    name: `babel-transform-mark-to-keep-dynamic-import`,\n    visitor: {\n      Program() {\n        const filename = this.file?.opts?.filename\n        if (!filename) {\n          return\n        }\n\n        if (absolutePaths.includes(filename)) {\n          // this is big hack - it relies on some babel plugins internal to basically\n          // do early return ( https://github.com/babel/babel/blob/3526b79c87863052f1c61ec0c49c0fc287ba32e6/packages/babel-plugin-transform-modules-commonjs/src/index.ts#L174 )\n          // on top of that `BabelFile` doesn't expose delete for the metadata,\n          // so we reach into internal `_map` to delete it","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/gatsbyjs/gatsby/blob/8b06340921ffdf23125a365b9c9923690cb62ce6/packages/babel-preset-gatsby-package/lib/babel-transform-mark-to-keep-dynamic-import.js#L12-L48","documentation":"Thrown by `babel-transform-mark-to-keep-dynamic-import` (babel-transform-mark-to-keep-dynamic-import.js:30) when `opts.keepDynamicImports` is set but is not an array. The plugin calls `.map()` on it, so a non-array would crash later; this guard fails fast with a clear message instead.","triggerScenarios":"Passing `keepDynamicImports: 'gatsby-plugin-theme-ui'` (string instead of array); passing an object; passing a single value rather than a list.","commonSituations":"Misreading the option type from docs and passing a single string; copy-pasting a config snippet that uses the wrong shape.","solutions":["Wrap the value in an array: `keepDynamicImports: ['gatsby-plugin-theme-ui']`.","Confirm the option type against the JSDoc (`@property {Array<string>} keepDynamicImports`)."],"exampleFix":"// before\nkeepDynamicImports(_unused, { keepDynamicImports: 'gatsby-plugin-theme-ui' })\n\n// after\nkeepDynamicImports(_unused, { keepDynamicImports: ['gatsby-plugin-theme-ui'] })","handlingStrategy":"validation","validationCode":"function keepDynamicImportsIsArray(opts) {\n  return Array.isArray(opts && opts.keepDynamicImports)\n}","typeGuard":"/** @returns {opts is { keepDynamicImports: string[] }} */\nfunction isStringArray(v) {\n  return Array.isArray(v) && v.every(x => typeof x === 'string')\n}","tryCatchPattern":null,"preventionTips":["Pass an array even for a single entry.","Validate option shapes at config load time.","Document the expected type next to the plugin registration."],"tags":["babel","config","dynamic-import","type-error"],"backgroundTag":null,"analyzedSha":"8b06340921ffdf23125a365b9c9923690cb62ce6","analyzedAt":"2026-08-13T02:36:21.405Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}