gatsby.js: "node.frontmatter.image is null"

Viewed 412

LAST EDIT: fixed. It was a naming convention. I am currently using this tree structure:

-pages --posts ---00X-post For pagination/programmatically works fine so far. And inside, md with its correspondent image (used as a thumbnail too). One of those had the naming wrong. Fixed. Now everything is working just fine.

EDIT and UPDATE:

Thank you for your quick answer. I tried that, nothing changed. I do believe it has to do with all the templates for pagination I am currently using. For example, the one in charge of creating page 2 and so in is this one:

import React from 'react';
import Layout from '../components/layout';
import Post from '../components/Post';
import { graphql } from 'gatsby';
import { Row, Col } from 'reactstrap'; 
import Sidebar from '../components/Sidebar'; 
import PaginationLinks from '../components/PaginationLinks'; 

const postList = (props) => {
    const posts = props.data.allMarkdownRemark.edges
    const { currentPage, numberOfPages } = props.pageContext 

    return (
        <Layout pageTitle>
        <h1 className='titles'>{`page ${currentPage}`}</h1>
            <Row>
                <Col>
                {posts.map(({node}) => (
                    <Post
                        key={node.id}
                        slug={node.fields.slug}
                        title={node.frontmatter.title}
                        author={node.frontmatter.author}
                        date={node.frontmatter.date}
                        body={node.excerpt}
                        tags={node.frontmatter.tags}
                        fluid={node.frontmatter.image.childImageSharp.fluid}
                    />
                ))}
                <PaginationLinks 
                currentPage={currentPage} 
                numberOfPages={numberOfPages} 
                    
                />
                </Col>
                <Col md='4'>
                    <Sidebar>

                    </Sidebar>
                </Col>
            </Row>
        </Layout>
    )

}

export const postListQuery = graphql`
    query postListQuery($skip: Int!, $limit: Int!) {
        allMarkdownRemark(
            sort: { fields: [frontmatter___date], order: DESC}
            limit: $limit
            skip: $skip 
        ) {
            edges {
                node {
                    id 
                    frontmatter {
                        title
                        date
                        author
                        tags
                        image {
                            childImageSharp {
                                fluid(maxWidth: 650, quality: 90) {
                                    ...GatsbyImageSharpFluid
                                }
                            }
                        }
                    }
                    fields {
                        slug
                    }
                    excerpt
                }
            }
        }
    }
`

export default postList

Same error messages appear when creating pages by tags/authors. If I delete the image field from the query, everything works. This is unusual.

While doing a simple blog project with Gatsby I run into either "TypeError: childImageSharp is undefined” or "node.frontmatter.image is null". This error message appears at random. By the time I started writing this, trying to access pages/2 only triggered it.

Here's index.js:

import React from "react"
import { graphql, StaticQuery } from 'gatsby'; 

import Layout from "../components/layout"
import SEO from "../components/seo"
import Post from '../components/Post'; 
import Sidebar from '../components/Sidebar'; 
import { Row, Col } from 'reactstrap'; 
import PaginationLinks from '../components/PaginationLinks'; 

const IndexPage = () => {

  const postsPerPage = 5; 
  let numberOfPages 

  return (
    <Layout>
    <SEO title="home" keywords={[`procedural`, `gatsby`]}/>
    <h1 className='titles'>procedural</h1>

    <Row>
      <Col>
        <StaticQuery 
        query={indexQuery}
        render={data => {

          numberOfPages = Math.ceil(
          data.allMarkdownRemark.totalCount / postsPerPage
          ); 

          return (
            <div>
              {
                data.allMarkdownRemark.edges.map(({ node }) => (
                  <Post 
                  key={node.id}
                  title={node.frontmatter.title}
                  author={node.frontmatter.author}
                  date={node.frontmatter.date}
                  slug={node.fields.slug}
                  body={node.excerpt}
                  fluid={node.frontmatter.image.childImageSharp.fluid}
                  tags={node.frontmatter.tags}
                  /> 
                ))
              }
              <PaginationLinks currentPage={1} numberOfPages={numberOfPages} />
            </div>
          )
        }}
        />
      </Col>
      <Col md='4'>
        <Sidebar>

        </Sidebar>
      </Col>
    </Row>

    </Layout>
  )
}

const indexQuery = graphql`
query {
  allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC}
    limit: 5
    ) {
    totalCount
    edges {
      node {
        id
        frontmatter {
          title
          date
          author
          tags
          image {
            childImageSharp {
              fluid(quality: 85, maxWidth: 960) {
                ...GatsbyImageSharpFluid
              }
            }
          }
        }
        fields {
          slug
        }
        excerpt
      }
    }
  }
}
`

export default IndexPage

Here's gatsby-node.js:

const path = require('path'); 
const { slugify } = require('./src/utils/utilityFunctions');
const authors = require('./src/utils/authors'); 
const _ = require('lodash'); 

// single post generator
exports.onCreateNode = ({ node, actions }) => {
    const { createNodeField } = actions
    if(node.internal.type === 'MarkdownRemark') {
        const slugFromTitle = slugify(node.frontmatter.title)
        createNodeField({
            node, 
            name: 'slug',
            value: slugFromTitle,
        })
    }
}

exports.createPages = async ({ actions, graphql }) => {
    const { createPage } = actions; 
    
    
    const templates = {
        singlePost: path.resolve('./src/templates/single-post.js'),
        tagsPage: path.resolve('./src/templates/tags-page.js'),
        tagPosts: path.resolve('./src/templates/tag-post.js'),
        postList: path.resolve('./src/templates/post-list.js'),
        authorPosts: path.resolve('./src/templates/author-posts.js'), 
    } 

    const res = await graphql(`
        {
            allMarkdownRemark {
                edges {
                    node {
                        frontmatter{
                            author
                            tags
                        }
                        fields {
                            slug
                        }
                    }
                }
            }
        }
    `)
    
    if(res.errors) return Promise.reject(res.errors)

    const posts = res.data.allMarkdownRemark.edges

    posts.forEach(({node}) => {
        createPage({
            path: node.fields.slug,
            component: templates.singlePost,
            context: {
                // passing slug, PENDING TAGS
                slug: node.fields.slug,
                // finding author imageUrl from authors.js and passing it to the single post template 

            },
        })
    })


            // creating post pages

    const postsPerPage = 5
    const numberOfPages = Math.ceil(posts.length / postsPerPage)

    Array.from({ length: numberOfPages }).forEach((_, index) => {
        const isFirstPage = index === 0
        const currentPage = index + 1

        // skip first page and go to index.js
        if (isFirstPage) return

        createPage({
            path: `/page/${currentPage}`,
            component: templates.postList,
            context: {
                limit: postsPerPage,
                skip: index * postsPerPage,
                numberOfPages: numberOfPages,
                currentPage: currentPage,
            },
            })
        })

        // tags PAGE GENERATOR; getting all tags
        let tags = []
        _.each(posts, edge => {
            if (_.get(edge, 'node.frontmatter.tags')) {
              tags = tags.concat(edge.node.frontmatter.tags)
            }
          })

        // account of tags, we're putting them like this: ['design', 'example', 'luck'] and also {design: X, example: Y, luck: z}
        let tagPostCounts = {}
        tags.forEach(tag => {
            tagPostCounts[tag] = (tagPostCounts[tag] || 0) + 1; 
        })

        tags = _.uniq(tags) //elimninate all duplicate entries 

        // create tags page here 
        createPage({
            path: `/tags`,
            component: templates.tagsPage,
            context: {
                tags,
                tagPostCounts,
            }
        })

        // tag post page creation here: 
        tags.forEach(tag => {
            createPage({
                path: `/tag/${_.kebabCase(tag)}`,
                component: templates.tagPosts,
                context: {
                    tag
                }
            })
        })

        // CREATING PAGES FOR EACH AUTHOR'S POSTS: 
        authors.forEach(author => {
            createPage({
                path: `/author/${slugify(author.name)}`,
                component: templates.authorPosts,
                context: {
                    authorName: author.name,
                    imageUrl: author.imageUrl, 
                }, 
            })
        })
}

here's gatsby-config.js:

  plugins: [
    `gatsby-plugin-sharp`,
    `gatsby-transformer-sharp`,
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-sass`,
    `gatsby-transformer-remark`,
    `gatsby-plugin-catch-links`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/pages`,
      },
    },
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `procedural`,
        short_name: `procedural`,
        start_url: `/`,
        background_color: `#663399`, // PLACEHOLDER
        theme_color: `#663399`, // PLACEHOLDER
        display: `minimal-ui`, // PLACEHOLDER
        icon: `src/images/logo.png`, // This path is relative to the root of the site.
      },
    },
  ],

And here's my single-post.js:

import React from 'react';
import Layout from '../components/layout'; 
import { graphql, Link } from 'gatsby'; 
import SEO from '../components/seo';
import { Badge, Card, CardBody, CardSubtitle } from 'reactstrap'; 
import Img from 'gatsby-image'; 
import { slugify } from '../utils/utilityFunctions'; 

const SinglePost = ({ data, pageContext }) => {
    const post = data.markdownRemark.frontmatter; 

    return (
        <Layout>
            <SEO title={post.title}/>
            <h1 className='postTitles'>{post.title}</h1>

                    <Card>
                        <Img className='card-image-top' fluid={post.image.childImageSharp.fluid}>

                        </Img>
                        <CardBody className='cardBody'>
                            <CardSubtitle>
                                <span className='text-info'>
                                    {post.date}
                                </span> by{' '}
                                <span className='text-info'>
                                    {post.author}
                                </span>
                            </CardSubtitle>
                            <div dangerouslySetInnerHTML={{ __html: data.markdownRemark.html }}>

                            </div>
                            <ul className='post-tags'>
                                {
                                    post.tags.map(tag => (
                                        <li key={tag}>
                                            <Link to={`/tag/${slugify(tag)}`}>
                                                <Badge className='myTags'>{tag}</Badge>
                                            </Link>
                                        </li>
                                    ))
                                }
                            </ul>
                            <br/>
                            <Link
                                to={'/'} 
                                className='myButton float-left'>
                                Go back
                            </Link>
                        </CardBody>

                    </Card>
                    <h3 className='text-center'>
                        Share this post
                    </h3>
                    <div className='text-center social-share-links'>
                        <ul>
                            <li>
                                <a href={'https://www.facebook.com/sharer/sharer.php?u=' + baseUrl + 
                                pageContext.slug}
                                className='facebook' target='_blank'
                                rel='noopener noreferrer'>
                                    <i className="fab fa-facebook-f fa-2x"/>
                                </a>
                            </li>
                            <li>
                                <a href={'https://www.twitter.com/share?url=' + 
                                baseUrl + 
                                pageContext.slug +
                                '&text=' +
                                post.title +
                                '&via' +
                                'twitterHandle'}
                                className='twitter' target='_blank'
                                rel='noopener noreferrer'>
                                    <i className="fab fa-twitter fa-2x"/>
                                </a>
                            </li>
                            <li>
                                <a href={'https://www.plus.google.com/share?url' + 
                                baseUrl + 
                                pageContext.slug
                                }
                                className='google' target='_blank'
                                rel='noopener noreferrer'>
                                    <i className="fab fa-google fa-2x"/>
                                </a>
                            </li>
                            <li>
                                <a href={'https://www.linkedin.com/shareArticle?url=' + 
                                baseUrl + 
                                pageContext.slug
                                }
                                className='linkedin' target='_blank'
                                rel='noopener noreferrer'>
                                    <i className="fab fa-linkedin fa-2x"/>
                                </a>
                            </li>
                        </ul>
                    </div>

        </Layout>
    )

}

export const postQuery = graphql`
    query blogPostBySlug($slug: String!) {
        markdownRemark(fields: { slug: { eq: $slug } }) {
            id
            html
            frontmatter {
                title
                author
                date
                tags
                image {
                    childImageSharp{
                        fluid(quality: 100, maxWidth: 960) {
                            ...GatsbyImageSharpFluid
                        }
                    }
                }

            }
        }

    }
`

export default SinglePost; 

Here's what happens when using gatsby develop:

$ gatsby develop
success open and validate gatsby-configs - 0.027s
success load plugins - 0.904s
success onPreInit - 0.031s
success initialize cache - 0.005s
success copy gatsby files - 0.081s
success onPreBootstrap - 0.014s
success createSchemaCustomization - 0.008s
success Checking for changed pages - 0.002s
success source and transform nodes - 0.126s
success building schema - 0.291s
info Total nodes: 110, SitePage nodes: 19 (use --verbose for breakdown)
success createPages - 0.061s
success Checking for changed pages - 0.001s
success createPagesStatefully - 0.087s
success update schema - 0.023s
success write out redirect data - 0.002s
success Build manifest and related icons - 0.103s
success onPostBootstrap - 0.109s
info bootstrap finished - 3.883s
success onPreExtractQueries - 0.002s
success extract queries from components - 0.419s
success write out requires - 0.027s
success run static queries - 0.030s - 2/2 65.79/s
success run page queries - 0.020s - 2/2 100.53/s
⠀
You can now view gatsby-starter-default in the browser.
⠀
  http://localhost:8000/
⠀
View GraphiQL, an in-browser IDE, to explore your site's data and schema
⠀
  http://localhost:8000/___graphql
⠀
Note that the development build is not optimized.
To create a production build, use gatsby build
⠀
success Building development bundle - 4.905s

Here's the error message when running gatsby build:

$ gatsby build
success open and validate gatsby-configs - 0.024s
success load plugins - 0.902s
success onPreInit - 0.047s
success delete html and css files from previous builds - 0.006s
success initialize cache - 0.004s
success copy gatsby files - 0.082s
success onPreBootstrap - 0.012s
success createSchemaCustomization - 0.008s
success Checking for changed pages - 0.001s
success source and transform nodes - 0.126s
success building schema - 0.276s
info Total nodes: 110, SitePage nodes: 19 (use --verbose for breakdown)
success createPages - 0.056s
success Checking for changed pages - 0.001s
success createPagesStatefully - 0.094s
success Cleaning up stale page-data - 0.006s
success update schema - 0.035s
success onPreExtractQueries - 0.003s
success extract queries from components - 0.499s
success write out redirect data - 0.002s
success Build manifest and related icons - 0.102s
success onPostBootstrap - 0.113s
info bootstrap finished - 5.462s
success run static queries - 0.021s - 2/2 96.19/s
success run page queries - 0.013s - 1/1 79.77/s
success write out requires - 0.005s
success Building production JavaScript and CSS bundles - 10.390s
success Rewriting compilation hashes - 0.003s
failed Building static HTML for pages - 2.388s

 ERROR #95313 

Building static HTML failed for path "/page/2"

See our docs page for more info on this error: https://gatsby.dev/debug-html


  26 |                         body={node.excerpt}
  27 |                         tags={node.frontmatter.tags}
> 28 |                         fluid={node.frontmatter.image.childImageSharp.fluid}  
     |                                                       ^
  29 |                     />
  30 |                 ))}
  31 |                 <PaginationLinks


  WebpackError: TypeError: Cannot read property 'childImageSharp' of null

  - post-list.js:28 
    src/templates/post-list.js:28:55

  - post-list.js:19 
    src/templates/post-list.js:19:24
1 Answers

You are using a page query in your IndexPage component, however, you are retrieving the data using a StaticQuery component. Change it to:

import React from "react"
import { graphql, StaticQuery } from 'gatsby'; 

import Layout from "../components/layout"
import SEO from "../components/seo"
import Post from '../components/Post'; 
import Sidebar from '../components/Sidebar'; 
import { Row, Col } from 'reactstrap'; 
import PaginationLinks from '../components/PaginationLinks'; 

const IndexPage = ({data}) => {

  const postsPerPage = 5; 
  let numberOfPages 

  return (
    <Layout>
    <SEO title="home" keywords={[`procedural`, `gatsby`]}/>
    <h1 className='titles'>procedural</h1>

    <Row>
      <Col>
            <div>
              {
                data.allMarkdownRemark.edges.map(({ node }) => (
                 {node.frontmatter.image && <Post 
                  key={node.id}
                  title={node.frontmatter.title}
                  author={node.frontmatter.author}
                  date={node.frontmatter.date}
                  slug={node.fields.slug}
                  body={node.excerpt}
                  fluid={node.frontmatter.image.childImageSharp.fluid}
                  tags={node.frontmatter.tags}
                  /> }
                ))
              }
              <PaginationLinks currentPage={1} numberOfPages={numberOfPages} />
            </div>
      </Col>
      <Col md='4'>
        <Sidebar>

        </Sidebar>
      </Col>
    </Row>

    </Layout>
  )
}

const indexQuery = graphql`
query {
  allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC}
    limit: 5
    ) {
    totalCount
    edges {
      node {
        id
        frontmatter {
          title
          date
          author
          tags
          image {
            childImageSharp {
              fluid(quality: 85, maxWidth: 960) {
                ...GatsbyImageSharpFluid
              }
            }
          }
        }
        fields {
          slug
        }
        excerpt
      }
    }
  }
}
`

export default IndexPage

The data fetched using pages queries, is stored under props. Since in the snippet above you are destructuring props as data (({data})), you don't need to trigger another query like you were doing, your data is already stored in data. So you can loop it in the same way you were doing.

Related