{"record":{"id":"5db549827417f656","repo":"gatsbyjs/gatsby","slug":"collection-page-builder-encountered-an-error-parsi","errorCode":null,"errorMessage":"Collection page builder encountered an error parsing the filepath. To use collection paths the schema to follow is {Model.field__subfield}. The problematic part is: ${part}.","messagePattern":"Collection page builder encountered an error parsing the filepath\\. To use collection paths the schema to follow is (.+?)\\. The problematic part is: (.+?)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/gatsby-plugin-page-creator/src/is-valid-collection-path-implementation.ts","lineNumber":29,"sourceCode":"  filePath: string,\n  reporter: Reporter\n): boolean {\n  const parts = filePath.split(sysPath.sep)\n  let passing = false\n  let errors = 0\n\n  parts.forEach(part => {\n    if (!part.includes(`{`) && !part.includes(`}`)) return\n\n    const model = Array.from(part.matchAll(/\\{([a-zA-Z_]\\w*)./g)) // Search for word before first dot, e.g. Model\n    const field = Array.from(part.matchAll(/.*?((?<=\\w\\.)[^}]*)}/g)) // Search for everything after the first dot, e.g. foo__bar (or in invalid case: foo.bar)\n    try {\n      if (\n        model.length === 0 ||\n        field.length === 0 ||\n        model.length !== field.length\n      ) {\n        throw new Error(errorMessage(part))\n      }\n\n      const models = Array.from(model, m => m[1])\n      const fields = Array.from(field, f => f[1])\n\n      for (const m of models) {\n        assert(m, /^[a-zA-Z_]\\w*$/, errorMessage(part)) // Check that Model is https://spec.graphql.org/draft/#sec-Names\n      }\n      for (const f of fields) {\n        assert(f, /^[a-zA-Z_][\\w_()]*$/, errorMessage(part)) // Check that field is foo__bar__baz (and not foo.bar.baz) + https://spec.graphql.org/draft/#sec-Names\n      }\n    } catch (e) {\n      reporter.panicOnBuild({\n        id: prefixId(CODES.CollectionPath),\n        context: {\n          sourceMessage: e.message,\n        },\n        filePath: filePath,","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/gatsbyjs/gatsby/blob/8b06340921ffdf23125a365b9c9923690cb62ce6/packages/gatsby-plugin-page-creator/src/is-valid-collection-path-implementation.ts#L11-L47","documentation":"gatsby-plugin-page-creator supports file-system routing with collection segments like `{Model.field__subfield}` (e.g. src/pages/{Product.name}.js). is-valid-collection-path-implementation.ts parses each path part and extracts the Model (word before the first dot) and the field chain (everything after the first dot) via regex. If either capture yields zero matches, or the counts of captured models and fields do not match, the part is rejected with this error. It indicates structurally malformed collection syntax (missing model, missing field, unbalanced braces, or extra dots).","triggerScenarios":"A file under src/pages whose name contains `{...}` but breaks the schema: `{.field}` (no Model), `{Model.}` (no field), `{Model.field.subfield}` (dots instead of __), `{Model.}` (trailing dot), or two collection markers in one segment like `{A.x}{B.y}` producing mismatched model/field counts. Also triggered by stray braces in a filename like `foo{bar}.js`.","commonSituations":"Coming from Next.js dynamic routes (`[slug]`) and using dots instead of the Gatsby `__` separator; copy-pasting a GraphQL field path with dots into the filename; accidentally leaving a literal `{` in a filename; renaming a model field but not the file.","solutions":["Rewrite the filename to the {Model.field} form using __ for nested fields, e.g. {Product.category__slug}.js.","Ensure exactly one {Model.field} token per path segment; split multiple tokens across separate path segments.","Remove any stray curly braces from filenames that are not meant to be collection markers.","Confirm the Model name matches an existing Gatsby node type (e.g. Mdx, MarkdownRemark) and the field is a valid GraphQL field on that type."],"exampleFix":"// before\nsrc/pages/{Product.category.slug}.js // dots are illegal in the field part\n\n// after\nsrc/pages/{Product.category__slug}.js // __ separates subfields","handlingStrategy":"validation","validationCode":"const COLLECTION_PART = /\\{([a-zA-Z_]\\w*)\\.([^}]+)\\}/;\nfunction isValidCollectionPart(part) {\n  if (!part.includes('{') && !part.includes('}')) return true;\n  const models = Array.from(part.matchAll(/\\{([a-zA-Z_]\\w*)\\./g));\n  const fields = Array.from(part.matchAll(/.*?((?<=\\w\\.)[^}]*)}/g));\n  return models.length > 0 && models.length === fields.length;\n}","typeGuard":"function isCollectionPath(p) {\n  return p.split('/').every(part => {\n    if (!part.includes('{')) return true;\n    const models = Array.from(part.matchAll(/\\{([a-zA-Z_]\\w*)\\./g));\n    const fields = Array.from(part.matchAll(/.*?((?<=\\w\\.)[^}]*)}/g));\n    return models.length > 0 && models.length === fields.length &&\n      models.every(m => /^[a-zA-Z_]\\w*$/.test(m[1]));\n  });\n}","tryCatchPattern":null,"preventionTips":["Use the {Model.field__subfield} form with __ for subfields, never dots.","Keep exactly one {Model.field} marker per path segment.","Add a prebuild lint that scans src/pages for malformed collection filenames."],"tags":["gatsby-plugin-page-creator","file-system-routing","collection-path","validation"],"backgroundTag":null,"analyzedSha":"8b06340921ffdf23125a365b9c9923690cb62ce6","analyzedAt":"2026-08-13T02:36:21.405Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}