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

  1. Change defaultDataLayer to a single plain object literal: { platform: 'gatsby', pageType: 'home' }
  2. If you need multiple data layer pushes, use a function: defaultDataLayer: function() { return { ... } }
  3. 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

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


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