Error: `siteUrl` does not exist on `siteMetadata` in the data returned from the query. How to resolve?

Viewed 307

When building my Gatsby website I get the below error. I've tried to delete and reinstall npm, update the plugins, deleting (Gatsby) cache, playing around with the siteUrl and all kinds of settings in the Gatsby config. But I can't seem to get rid of the error. The development environment works fine.

github: https://github.com/bartfluitsma/gatsby-bart-fluitsma

**Error console log**

ERROR #11321  PLUGIN

"gatsby-plugin-sitemap" threw an error while running the onPostBuild lifecycle:

`siteUrl` does not exist on `siteMetadata` in the data returned from the query.
Add this to your `siteMetadata` object inside gatsby-config.js or add this to your custom query or provide a custom `resolveSiteUrl` function.
https://www.gatsbyjs.com/plugins/gatsby-plugin-sitemap/#api-reference


  47 |             errors = _yield$graphql.errors;
  48 |             _context.next = 9;
> 49 |             return Promise.resolve(resolveSiteUrl(queryRecords)).catch(function (err) {
     |                                    ^
  50 |               return reporter.panic(_internals.REPORTER_PREFIX + " Error resolving Site URL", err);
  51 |             });
  52 |

File: node_modules\gatsby-plugin-sitemap\gatsby-node.js:49:36



  Error: `siteUrl` does not exist on `siteMetadata` in the data returned from the query.
  Add this to your `siteMetadata` object inside gatsby-config.js or add this to your custom query or provide a custom `resolveSiteUrl` function.
  https://www.gatsbyjs.com/plugins/gatsby-plugin-sitemap/#api-reference

  - internals.js:62 resolveSiteUrl
    [gatsby-bart-fluitsma]/[gatsby-plugin-sitemap]/internals.js:62:11

  - gatsby-node.js:49 _callee$
    [gatsby-bart-fluitsma]/[gatsby-plugin-sitemap]/gatsby-node.js:49:36


not finished onPostBuild - 0.480s

Gatsby-config.js

module.exports = {
  siteMetadata: {
    title: `Bart Fluitsma`,
    description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
    author: `@gatsbyjs`,
    siteUrl: `http://bartfluitsma.com`,
  },
  plugins: [
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-image`,
    'gatsby-plugin-postcss',
    {
      resolve: `gatsby-plugin-google-fonts-with-attributes`,
      options: {
        fonts: [
          `montserrat\:300,400,400i,600,900`,
        ],
        display: 'swap',
        attributes: {
          rel: "stylesheet preload prefetch",
        },
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    }, {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/locales`,
        name: `locale`
      }
    },
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `Web development | Bart Fluitsma`,
        short_name: `Bart develops`,
        start_url: `/`,
        background_color: `#663399`,
        // This will impact how browsers show your PWA/website
        // https://css-tricks.com/meta-theme-color-and-trickery/
        // theme_color: `#663399`,
        display: `minimal-ui`,
        icon: `src/images/logo-bart-fluitsma-web-design.svg`, // This path is relative to the root of the site.
      },
    },
    {
      resolve: `gatsby-plugin-react-i18next`,
      options: {
        localeJsonSourceName: `locale`, // name given to `gatsby-source-filesystem` plugin.
        languages: [`en`, `nl`],
        defaultLanguage: `en`,
        // if you are using Helmet, you must include siteUrl, and make sure you add http:https
        siteUrl: `https://bartfluitsma.com`,
        // you can pass any i18next options
        i18nextOptions: {
          interpolation: {
            escapeValue: false // not needed for react as it escapes by default
          },
          keySeparator: false,
          nsSeparator: false
        },
        pages: [
          {
            matchPath: '/:lang?/blog/:uid',
            getLanguageFromPath: true
          },
        ]
      }
    },
    // this (optional) plugin enables Progressive Web App + Offline functionality
    // To learn more, visit: https://gatsby.dev/offline
    // `gatsby-plugin-offline`,
    {
      resolve: 'gatsby-plugin-sitemap',
      options: {
        excludes: ['/**/404', '/**/404.html'],
        query: `
            {
              site {
                siteMetadata {
                  siteUrl
                }
              }
              allSitePage(filter: {context: {i18n: {routed: {eq: false}}}}) {
                edges {
                  node {
                    context {
                      i18n {
                        defaultLanguage
                        languages
                        originalPath
                      }
                    }
                    path
                  }
                }
              }
            }
          `,
        serialize: ({ site, allSitePage }) => {
          return allSitePage.edges.map((edge) => {
            const { languages, originalPath, defaultLanguage } = edge.node.context.i18n;
            const { siteUrl } = site.siteMetadata;
            const url = siteUrl + originalPath;
            const links = [
              { lang: defaultLanguage, url },
              { lang: 'x-default', url }
            ];
            languages.forEach((lang) => {
              if (lang === defaultLanguage) return;
              links.push({ lang, url: `${siteUrl}/${lang}${originalPath}` });
            });
            return {
              url,
              changefreq: 'daily',
              priority: originalPath === '/' ? 1.0 : 0.7,
              links
            };
          });
        }
      }
    },
  ],
}
2 Answers

The error is thrown by gatsby-plugin-sitemap. Try adding the resolveSiteUrl method in your configuration like:

const siteUrl = process.env.URL || `https://fallback.net`

resolveSiteUrl: () => siteUrl,

Applied to your code:

const siteUrl = process.env.URL || `https://fallback.net`

module.exports = {
  plugins: [
    {
      resolve: "gatsby-plugin-sitemap",
      options: {
        excludes: ["/**/404", "/**/404.html"],
        query: `
            {
              site {
                siteMetadata {
                  siteUrl
                }
              }
              allSitePage(filter: {context: {i18n: {routed: {eq: false}}}}) {
                edges {
                  node {
                    context {
                      i18n {
                        defaultLanguage
                        languages
                        originalPath
                      }
                    }
                    path
                  }
                }
              }
            }
          `,
        resolveSiteUrl: () => siteUrl,
        serialize: ({ site, allSitePage }) => {
          return allSitePage.edges.map((edge) => {
            const { languages, originalPath, defaultLanguage } =
              edge.node.context.i18n;
            const { siteUrl } = site.siteMetadata;
            const url = siteUrl + originalPath;
            const links = [
              { lang: defaultLanguage, url },
              { lang: "x-default", url },
            ];
            languages.forEach((lang) => {
              if (lang === defaultLanguage) return;
              links.push({ lang, url: `${siteUrl}/${lang}${originalPath}` });
            });
            return {
              url,
              changefreq: "daily",
              priority: originalPath === "/" ? 1.0 : 0.7,
              links,
            };
          });
        },
      },
    },
  ],
};

Change the siteUrl and the fallback URL accordingly if you are not setting it in your environment file

Your siteUrl issue just masks that the query was invalid, as the context is not available in gatsby >= 4 anymore, as you found out after fixing the siteUrl.

You may have used this query from the gatsby-plugin-react-i18next docs to support a sitemap.

In order to make it work, I found you have to 1. create the context yourself, and 2. adjust the queries

  1. Create your context through gatsby-node.js (credit wilsonvolker)
/**
 * Workaround for missing sitePage.context:
 * Used for generating sitemap with `gatsby-plugin-react-i18next` and `gatsby-plugin-sitemap` plugins
 * https://www.gatsbyjs.com/docs/reference/release-notes/migrating-from-v3-to-v4/#field-sitepagecontext-is-no-longer-available-in-graphql-queries
 */
exports.createSchemaCustomization = ({ actions }) => {
    const { createTypes } = actions
    createTypes(`
    type SitePage implements Node {
      context: SitePageContext
    }
    type SitePageContext {
      i18n: i18nContext
    }
    type i18nContext {
        language: String,
        languages: [String],
        defaultLanguage: String,
        originalPath: String
        routed: Boolean
    }
  `)
}
  1. It looks like the serialize function proposed in the i18next doesn't work as-is anymore since it apparently receives a single node, not the full graphql response. So, a few changes in gatsby-config.js to make it work again (this assumes you have a global siteUrl variable available):
query: `
  {
    site {
      siteMetadata {
        siteUrl
      }
    }
    allSitePage(filter: {context: {i18n: {routed: {eq: false}}}}) {
      nodes {
        context {
          i18n {
            defaultLanguage
            languages
            originalPath
          }
        }
        path
      }
    }
  }
`,
serialize: (node) => {
  const { languages, originalPath, defaultLanguage } = node.context.i18n
  const url = siteUrl + originalPath
  const links = [
    { lang: defaultLanguage, url },
    { lang: 'x-default', url },
  ]
  languages.forEach((lang) => {
    if (lang === defaultLanguage) return
    links.push({ lang, url: `${siteUrl}/${lang}${originalPath}` })
  })
  return {
    url,
    changefreq: 'daily',
    priority: originalPath === '/' ? 1.0 : 0.7,
    links,
  }
},
Related