Gatsby: Variable "$skip" of required type "Int!" was not provided

Created on 12 May 2020  ·  7Comments  ·  Source: gatsbyjs/gatsby

Hello all,

can anybody help me to fix the error "Variable "$skip" of required type "Int!" was not provided." ?

I followed instruction below;
https://www.gatsbyjs.org/docs/adding-pagination/

I am trying to add pagination on top page of my blog, but got stuck with error "Variable "$skip" of required type "Int!" was not provided." I got also another error "Variable "$limit" of required type "Int!" was not provided.", and I guess the cause is the same.

If somebody would kindly help me to fix it, it would be highly appreciated.

And, here is my code;

src/pages/index.jsx

import React from 'react'
import Helmet from 'react-helmet'
import { graphql } from 'gatsby'
import Layout from '../components/Layout'
import Post from '../components/Post'
import Sidebar from '../components/Sidebar'

class IndexRoute extends React.Component {
  render() {
    const items = []
    const { title, subtitle } = this.props.data.site.siteMetadata
    const posts = this.props.data.allMarkdownRemark.edges
    posts.forEach(post => {
      items.push(<Post data={post} key={post.node.fields.slug} />)
    })

    return (
      <Layout>
        <div>
          <Helmet>
            <title>{title}</title>
            <meta name="description" content={subtitle} />
          </Helmet>
          {/* commented out by kinnniku <Sidebar {...this.props} /> */}
          <div className="content">
            <div className="content__inner">{items}</div>
          </div>
          <Sidebar {...this.props} />
        </div>
      </Layout>
    )
  }
}

export default IndexRoute

debugger

export const pageQuery = graphql`

  # original is below
  # query IndexQuery{

  query IndexQuery($skip: Int!, $limit: Int!){
    site {
      siteMetadata {
        title
        subtitle
        copyright
        menu {
          label
          path
        }
        author {
          name
          twitter
          github
        }
      }
    }
    allMarkdownRemark(
      # this is comment
      sort: { order: DESC, fields: [frontmatter___date] }
      # original is limit: 1000
      limit: $limit
      filter: { frontmatter: { layout: { eq: "post" }, draft: { ne: true } } , fields: { draft: { eq: false } } }
      # skip is added
      skip: $skip
      ) {
      edges {
        node {
          fields {
            slug
            categorySlug
          }
          frontmatter {
            title
            featuredImage {
              childImageSharp {
                sizes(maxWidth: 630) {
                  ...GatsbyImageSharpSizes
                }
              }
            }
            path
            date
            category
            description
          }
        }
      }
    }
  }
`

gatsby-node.js

const _ = require('lodash')
const Promise = require('bluebird')
const path = require('path')
const slash = require('slash')

exports.createPages = ({ graphql, actions }) => {

  const { createPage } = actions

  return new Promise((resolve, reject) => {
    const postTemplate = path.resolve('./src/templates/post-template.jsx')
    const pageTemplate = path.resolve('./src/templates/page-template.jsx')
    const tagTemplate = path.resolve('./src/templates/tag-template.jsx')

    // Kinniku added one line below for pagination
    const blogPostList = path.resolve('./src/pages/index.jsx')

    const categoryTemplate = path.resolve(
      './src/templates/category-template.jsx'
    )

    graphql(`
      {
        allMarkdownRemark(
          limit: 1000
          filter: { frontmatter: { draft: { ne: true } } , fields: { draft: { eq: false } } }
        ) {
          edges {
            node {
              fields {
                slug
              }
              frontmatter {
                tags
                layout
                category
              }
            }
          }
        }
      }
    `).then(result => {
      if (result.errors) {
        console.log(result.errors)
        reject(result.errors)
      }

      // Kinniku added from here

      const posts = result.data.allMarkdownRemark.edges

      // Create list of posts pages
      // https://www.gatsbyjs.org/docs/adding-pagination/
      const postsPerPage = 10

      const numPages = Math.ceil(posts.length / postsPerPage)
      Array.from({ length: numPages }).forEach((_, index) => {
        const withPrefix = pageNumber =>
          pageNumber === 1 ? `/` : `/page/${pageNumber}`
        const pageNumber = index + 1
        createPage({
          path: withPrefix(pageNumber),
          component: blogPostList,
          context: {
            limit: postsPerPage,
            skip: index * postsPerPage,
            current: pageNumber,
            total: numPages,
            hasNext: pageNumber < numPages,
            nextPath: withPrefix(pageNumber + 1),
            hasPrev: index > 0,
            prevPath: withPrefix(pageNumber - 1),
          },
        })
      })

      // Create blog posts pages.

      posts.forEach((post, index) => {
        const previous =
          index === posts.length - 1 ? null : posts[index + 1].node
        const next = index === 0 ? null : posts[index - 1].node

        createPage({
          path: `/post${post.node.fields.slug}`,
          component: postTemplate,
          context: {
            slug: post.node.fields.slug,
            previous,
            next,
          },
        })
      })

      // kinniku added until here

      _.each(result.data.allMarkdownRemark.edges, edge => {
        if (_.get(edge, 'node.frontmatter.layout') === 'page') {
          createPage({
            path: edge.node.fields.slug,
            component: slash(pageTemplate),
            context: { slug: edge.node.fields.slug },
          })
        } else if (_.get(edge, 'node.frontmatter.layout') === 'post') {
          createPage({
            path: edge.node.fields.slug,
            component: slash(postTemplate),
            context: { slug: edge.node.fields.slug },
          })

          let tags = []
          if (_.get(edge, 'node.frontmatter.tags')) {
            tags = tags.concat(edge.node.frontmatter.tags)
          }

          tags = _.uniq(tags)
          _.each(tags, tag => {
            const tagPath = `/tags/${_.kebabCase(tag)}/`
            createPage({
              path: tagPath,
              component: tagTemplate,
              context: { tag },
            })
          })

          let categories = []
          if (_.get(edge, 'node.frontmatter.category')) {
            categories = categories.concat(edge.node.frontmatter.category)
          }

          categories = _.uniq(categories)
          _.each(categories, category => {
            const categoryPath = `/categories/${_.kebabCase(category)}/`
            createPage({
              path: categoryPath,
              component: categoryTemplate,
              context: { category },
            })
          })
        }
      })

      resolve()
    })
  })


}

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions

  if (node.internal.type === 'File') {
    const parsedFilePath = path.parse(node.absolutePath)
    const slug = `/${parsedFilePath.dir.split('---')[1]}/`
    createNodeField({ node, name: 'slug', value: slug })
  } else if (
    node.internal.type === 'MarkdownRemark' &&
    typeof node.slug === 'undefined'
  ) {
    const fileNode = getNode(node.parent)
    let slug = fileNode.fields.slug
    if (typeof node.frontmatter.path !== 'undefined') {
      slug = node.frontmatter.path
    }
    createNodeField({
      node,
      name: 'slug',
      value: slug,
    })

    if (node.frontmatter.tags) {
      const tagSlugs = node.frontmatter.tags.map(
        tag => `/tags/${_.kebabCase(tag)}/`
      )
      createNodeField({ node, name: 'tagSlugs', value: tagSlugs })
    }

    if (typeof node.frontmatter.category !== 'undefined') {
      const categorySlug = `/categories/${_.kebabCase(
        node.frontmatter.category
      )}/`
      createNodeField({ node, name: 'categorySlug', value: categorySlug })
    }
  }
}
awaiting author response question or discussion

All 7 comments

is this the repo with the error?

https://github.com/kinnikumegane/myblog

mhhh - i see there some minor differences to your posted code snippets - i have to place your snippets into your repo

i found the error:

  const blogPostList = path.resolve('./src/pages/index.jsx')

your template get processed one time more than expected: when it automatic reads the pages directory - and in this case there is no context with the variables.

the solution is to move the template out of the pages directory:

  const blogPostList = path.resolve('./src/templates/post-list-template.jsx')

please tell me if my solution works for you.

feel free to reopen this issue, when it is not solved

Hello @muescha

thanks a lot for your support, and your support worked !!!

What I have done is to create 'blog-list-template.jsx' file under templates directory.
And, deleted index.jsx under pages directory.

Here is revised code;

blog-list-template.jsx

import React from 'react'
import Helmet from 'react-helmet'
import { graphql } from 'gatsby'
import Layout from '../components/Layout'
import Post from '../components/Post'
import Sidebar from '../components/Sidebar'
import { Link } from 'gatsby'

class BlogList extends React.Component {
  render() {
    const items = []
    const { title, subtitle } = this.props.data.site.siteMetadata
    const posts = this.props.data.allMarkdownRemark.edges
    const {
      current,
      total,
      hasNext,
      hasPrev,
      nextPath,
      prevPath,
    } = this.props.pageContext

    posts.forEach(post => {
      items.push(<Post data={post} key={post.node.fields.slug} />)
    })

    return (
      <Layout>
        <div>
          <Helmet>
            <title>{title}</title>
            <meta name="description" content={subtitle} />
          </Helmet>
          {/* commented out by kinnniku <Sidebar {...this.props} /> */}
          <div className="content">
            <div className="content__inner">{items}</div>
            <ul
              style={{
                display: `flex`,
                flexWrap: `wrap`,
                justifyContent: `space-between`,
                listStyle: `none`,
                paddingLeft: 30,
                paddingRight: 30,
              }}
            >
              <li>
                {hasPrev && (
                  <Link to={prevPath} rel="prev">
                    ← Prev
                  </Link>
                )}
              </li>
              <li>
                {current} of {total}
              </li>
              <li>
                {hasNext && (
                  <Link to={nextPath} rel="next">
                    Next →
                  </Link>
                )}
              </li>
            </ul>

          </div>
          <Sidebar {...this.props} />
        </div>
      </Layout>
    )
  }
}

export default BlogList

export const pageQuery = graphql`

  # original is below
  # query IndexQuery{

  query blogListQuery($skip: Int!, $limit: Int!){
    site {
      siteMetadata {
        title
        subtitle
        copyright
        menu {
          label
          path
        }
        author {
          name
          twitter
          github
        }
      }
    }
    allMarkdownRemark(
      # this is comment
      sort: { order: DESC, fields: [frontmatter___date] }
      # original is limit: 1000
      limit: $limit
      filter: { frontmatter: { layout: { eq: "post" }, draft: { ne: true } } , fields: { draft: { eq: false } } }
      # skip is added
      skip: $skip
      ) {
      edges {
        node {
          fields {
            slug
            categorySlug
          }
          frontmatter {
            title
            featuredImage {
              childImageSharp {
                sizes(maxWidth: 630) {
                  ...GatsbyImageSharpSizes
                }
              }
            }
            path
            date
            category
            description
          }
        }
      }
    }
  }
`

gatsby-node.js

const _ = require('lodash')
const Promise = require('bluebird')
const path = require('path')
const slash = require('slash')

exports.createPages = ({ graphql, actions }) => {

  const { createPage } = actions

  return new Promise((resolve, reject) => {
    const postTemplate = path.resolve('./src/templates/post-template.jsx')
    const pageTemplate = path.resolve('./src/templates/page-template.jsx')
    const tagTemplate = path.resolve('./src/templates/tag-template.jsx')

    // Kinniku added one line below for paginationmeikakun
    const blogPostList = path.resolve('./src/templates/blog-list-template.jsx')

    const categoryTemplate = path.resolve('./src/templates/category-template.jsx')

    graphql(`
      {
        allMarkdownRemark(
          limit: 1000
          filter: { frontmatter: { draft: { ne: true } } , fields: { draft: { eq: false } } }
        ) {
          edges {
            node {
              fields {
                slug
              }
              frontmatter {
                tags
                layout
                category
              }
            }
          }
        }
      }
    `).then(result => {
      if (result.errors) {
        console.log(result.errors)
        reject(result.errors)
      }

      // Kinniku added from here

      const posts = result.data.allMarkdownRemark.edges

      // following codes are added by Kinniku
      // because posts.length returns the number of "posts" plus "pages", posts.length can not be used to calculate number of pages
      // therefore, we need to use "count" which counts only the number of items includes the link '/posts'
      let count = 0
      posts.forEach((post) => {
        if(post.node.fields.slug.includes('/posts')){

          count = count + 1
        } else{

        }
      })

      // Create list of posts pages
      // https://www.gatsbyjs.org/docs/adding-pagination/
      const postsPerPage = 6

      // posts.length was replaced with count
      let numPages = Math.ceil(count / postsPerPage)

      Array.from({ length: numPages }).forEach((_, index) => {
        const withPrefix = pageNumber => pageNumber === 1 ? `/` : `/page/${pageNumber}`
        const pageNumber = index + 1
        createPage({
          path: withPrefix(pageNumber),
          component: blogPostList,
          context: {
            limit: postsPerPage,
            skip: index * postsPerPage,
            current: pageNumber,
            total: numPages,
            hasNext: pageNumber < numPages,
            nextPath: withPrefix(pageNumber + 1),
            hasPrev: index > 0,
            prevPath: withPrefix(pageNumber - 1),
          },
        })
      })

      // Create blog posts pages.

      posts.forEach((post, index) => {
        const previous = index === posts.length - 1 ? null : posts[index + 1].node
        const next = index === 0 ? null : posts[index - 1].node

        createPage({
          path: `/post${post.node.fields.slug}`,
          component: postTemplate,
          context: {
            slug: post.node.fields.slug,
            previous,
            next,
          },
        })
      })

      // kinniku added until here

      _.each(result.data.allMarkdownRemark.edges, edge => {
        if (_.get(edge, 'node.frontmatter.layout') === 'page') {
          createPage({
            path: edge.node.fields.slug,
            component: slash(pageTemplate),
            context: { slug: edge.node.fields.slug },
          })
        } else if (_.get(edge, 'node.frontmatter.layout') === 'post') {

          createPage({
            path: edge.node.fields.slug,
            component: slash(postTemplate),
            context: { slug: edge.node.fields.slug },
          })

          let tags = []
          if (_.get(edge, 'node.frontmatter.tags')) {
            tags = tags.concat(edge.node.frontmatter.tags)
          }

          tags = _.uniq(tags)
          _.each(tags, tag => {
            const tagPath = `/tags/${_.kebabCase(tag)}/`
            createPage({
              path: tagPath,
              component: tagTemplate,
              context: { tag },
            })
          })

          let categories = []
          if (_.get(edge, 'node.frontmatter.category')) {
            categories = categories.concat(edge.node.frontmatter.category)
          }

          categories = _.uniq(categories)
          _.each(categories, category => {
            const categoryPath = `/categories/${_.kebabCase(category)}/`
            createPage({
              path: categoryPath,
              component: categoryTemplate,
              context: { category },
            })
          })
        }
      })

      resolve()
    })
  })


}

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions

  if (node.internal.type === 'File') {
    const parsedFilePath = path.parse(node.absolutePath)
    const slug = `/${parsedFilePath.dir.split('---')[1]}/`
    createNodeField({ node, name: 'slug', value: slug })
  } else if (
    node.internal.type === 'MarkdownRemark' &&
    typeof node.slug === 'undefined'
  ) {
    const fileNode = getNode(node.parent)
    let slug = fileNode.fields.slug
    if (typeof node.frontmatter.path !== 'undefined') {
      slug = node.frontmatter.path
    }
    createNodeField({
      node,
      name: 'slug',
      value: slug,
    })

    if (node.frontmatter.tags) {
      const tagSlugs = node.frontmatter.tags.map(
        tag => `/tags/${_.kebabCase(tag)}/`
      )
      createNodeField({ node, name: 'tagSlugs', value: tagSlugs })
    }

    if (typeof node.frontmatter.category !== 'undefined') {
      const categorySlug = `/categories/${_.kebabCase(
        node.frontmatter.category
      )}/`
      createNodeField({ node, name: 'categorySlug', value: categorySlug })
    }
  }
}

great.

thank you for the status update.

i added a feature request to have better hints:

  • #24125 Feature Request: better error message if templates in /pages/ and get an error

Yep, I saw it, and thanks for sharing your expertise !
I could learn how documentation should look like )

Was this page helpful?
0 / 5 - 0 ratings