gatsbyjs/gatsby · error
Oops the plugin option "defaultDataLayer" should be a plain
Error message
Oops the plugin option "defaultDataLayer" should be a plain object. "${dataLayer}" is not valid. What it means
The gatsby-plugin-google-tagmanager plugin validates the 'defaultDataLayer' option inside generateDefaultDataLayer (gatsby-ssr.js:26). It accepts either a function (dataLayer.type === 'function') or a plain object. A plain object is defined as dataLayer.type === 'object' AND dataLayer.value.constructor === Object — meaning the value must be a literal {} (Object constructor), not an array, Map, class instance, Date, or any subclass. If neither condition holds, reporter.panic halts the build. The dataLayer is Gatsby's pre-processed representation where .type is the JS typeof result and .value is the raw user-supplied value.
Source
Thrown at packages/gatsby-plugin-google-tagmanager/src/gatsby-ssr.js:27
selfHostedPath,
}) => stripIndent`
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'${selfHostedOrigin}/${selfHostedPath}?id='+i+dl+'${environmentParamStr}';f.parentNode.insertBefore(j,f);
})(window,document,'script','${dataLayerName}', '${id}');`
const generateGTMIframe = ({ id, environmentParamStr, selfHostedOrigin }) =>
oneLine`<iframe src="${selfHostedOrigin}/ns.html?id=${id}${environmentParamStr}" height="0" width="0" style="display: none; visibility: hidden" aria-hidden="true"></iframe>`
const generateDefaultDataLayer = (dataLayer, reporter, dataLayerName) => {
let result = `window.${dataLayerName} = window.${dataLayerName} || [];`
if (dataLayer.type === `function`) {
result += `window.${dataLayerName}.push((${dataLayer.value})());`
} else {
if (dataLayer.type !== `object` || dataLayer.value.constructor !== Object) {
reporter.panic(
`Oops the plugin option "defaultDataLayer" should be a plain object. "${dataLayer}" is not valid.`
)
}
result += `window.${dataLayerName}.push(${JSON.stringify(
dataLayer.value
)});`
}
return stripIndent`${result}`
}
exports.onRenderBody = (
{ setHeadComponents, setPreBodyComponents, reporter },
{
id,
includeInDevelopment = false,
gtmAuth,View on GitHub (pinned to 8b06340921)
Solutions
- Change defaultDataLayer to a single plain object literal: { platform: 'gatsby', pageType: 'home' }
- If you need multiple data layer pushes, use a function: defaultDataLayer: function() { return { ... } }
- Remove the option entirely if you don't need a default data layer push.
Example fix
// before (gatsby-config.js)
{
resolve: `gatsby-plugin-google-tagmanager`,
options: {
id: `GTM-XXXX`,
defaultDataLayer: [{ platform: `gatsby` }], // array — triggers panic
},
},
// after
{
resolve: `gatsby-plugin-google-tagmanager`,
options: {
id: `GTM-XXXX`,
defaultDataLayer: { platform: `gatsby` }, // plain object
},
}, Defensive patterns
Strategy: type-guard
Validate before calling
// Before passing defaultDataLayer to gatsby-config, validate it
function isPlainObject(v) {
return typeof v === 'object' && v !== null && !Array.isArray(v) && v.constructor === Object
}
const defaultDataLayer = { platform: 'gatsby' }
if (!isPlainObject(defaultDataLayer) && typeof defaultDataLayer !== 'function') {
throw new Error('defaultDataLayer must be a plain object or function')
} Type guard
function isPlainObject(v: unknown): v is Record<string, unknown> {
return typeof v === 'object' &&
v !== null &&
!Array.isArray(v) &&
v.constructor === Object
}
// Usage:
const dataLayer = pluginOptions.defaultDataLayer
if (typeof dataLayer === 'function') {
// valid: function type
} else if (!isPlainObject(dataLayer)) {
throw new Error('defaultDataLayer must be a plain object')
} Prevention
- Always use a literal object {} for defaultDataLayer, never an array
- Remember GTM's runtime dataLayer is an array, but the plugin option expects an object
- Run a type check on plugin options before starting the build
When it happens
Trigger: Passing an array (e.g. defaultDataLayer: [{ page: 'home' }]) instead of a plain object. Passing a class instance, Map, Set, Date, or any non-literal object whose constructor is not the global Object. Passing a string or number that Gatsby did not pre-classify as a function type.
Common situations: Copying a dataLayer array from GTM documentation (GTM expects an array at runtime, but the plugin option wants an object). Migrating from a manual GTM snippet where dataLayer was an array. Passing a JSON-parsed value that is actually an array.
Related errors
- gatsby-plugin-page-creator_12107
- Invalid plugin options for "gatsby-plugin-sitemap":
- Cannot specify both JPG and PNG formats
- A languageExtension needs to be defined as an object. Given
- A languageExtension needs to contain 'language' and 'extend'
AI-assisted analysis of gatsbyjs/gatsby@8b06340921 (2026-08-13).
Data as JSON: /api/errors/10f838e4ab3e6cf5.
Report an issue: GitHub.