{"record":{"id":"d0cb673aa20fcb4b","repo":"vercel/next.js","slug":"failed-to-resolve-pattern-patterns-join","errorCode":null,"errorMessage":"Failed to resolve pattern \"${patterns.join(',')}\": ${error.message}","messagePattern":"Failed to resolve pattern \"(.+?)\": (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/next/src/lib/resolve-build-paths.ts","lineNumber":100,"sourceCode":"      : `{${includePatterns.join(',')}}`\n\n  try {\n    const matches = (await glob(combinedPattern, {\n      cwd: projectDir,\n      ignore: excludePatterns,\n    })) as string[]\n\n    if (matches.length === 0) {\n      Log.warn(`Pattern \"${patterns.join(',')}\" did not match any files`)\n    }\n\n    for (const file of matches) {\n      if (!fs.statSync(path.join(projectDir, file)).isDirectory()) {\n        categorizeAndAddPath(file, appPaths, pagePaths, validFileMatcher)\n      }\n    }\n  } catch (error) {\n    throw new Error(\n      `Failed to resolve pattern \"${patterns.join(',')}\": ${\n        isError(error) ? error.message : String(error)\n      }`\n    )\n  }\n\n  return {\n    appPaths: Array.from(appPaths).sort(),\n    pagePaths: Array.from(pagePaths).sort(),\n  }\n}\n\n/**\n * When the project keeps its `app/` or `pages/` directory under `src/`, prepend\n * `src/` to bare patterns so the glob actually matches files on disk. Patterns\n * that already include the `src/` prefix are returned unchanged.\n */\nfunction addSrcPrefixIfNeeded(","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/vercel/next.js/blob/0ae8c72462952df163f1b1e0726641bc5b40dc93/packages/next/src/lib/resolve-build-paths.ts#L82-L118","documentation":"Thrown by resolveBuildPaths() when the underlying glob library rejects the combined include pattern while resolving build paths for the App/Pages routers. Next.js wraps the glob error to surface which pattern(s) failed so you can correct the path spec. It fires during build/dev startup when Next.js enumerates route files from user-supplied or default path patterns.","triggerScenarios":"Calling resolveBuildPaths() with a malformed glob pattern (e.g. unbalanced braces, invalid brace-expansion like '{a,b', or a pattern with illegal characters). Also triggered when escapeBrackets() or addSrcPrefixIfNeeded() produce a combined pattern that the compiled glob library cannot parse.","commonSituations":"A dynamic-route bracket pattern that was not escaped correctly, a typo in a comma-separated path list fed to the build, or an upgrade that changed how brace expansion is combined (the code joins multiple includes via {p1,p2}). Rare in normal projects; more likely in custom tooling or after editing app/pages directory structure.","solutions":["Check the pattern printed in the message and validate it as a glob expression (balance braces, escape literal brackets/braces).","If using dynamic-route segments in the pattern, ensure they are well-formed ([slug], [...slug], [[...slug]]) so escapeBrackets can process them.","Reduce the pattern to a single include to isolate which entry breaks the combined {a,b} expansion.","Run a standalone glob (e.g. via the 'glob' package) against projectDir to reproduce the parser error outside Next.js."],"exampleFix":"// before\nresolveBuildPaths(['app/blog/[slug/page.tsx'], projectDir, pageExtensions)\n// after (close the bracket)\nresolveBuildPaths(['app/blog/[slug]/page.tsx'], projectDir, pageExtensions)","handlingStrategy":"validation","validationCode":"import globOriginal from 'next/dist/compiled/glob'\nimport { promisify } from 'util'\nconst glob = promisify(globOriginal)\n\nasync function validatePattern(pattern, cwd) {\n  try { await glob(pattern, { cwd }) }\n  catch (e) { throw new Error(`Pattern '${pattern}' is invalid: ${e.message}`) }\n}","typeGuard":"function isValidGlob(p: string): boolean {\n  // basic brace/bracket balance check\n  let braces = 0, brackets = 0\n  for (const ch of p) {\n    if (ch === '{') braces++\n    if (ch === '}') braces--\n    if (ch === '[') brackets++\n    if (ch === ']') brackets--\n    if (braces < 0 || brackets < 0) return false\n  }\n  return braces === 0 && brackets === 0\n}","tryCatchPattern":"try {\n  const paths = await resolveBuildPaths(patterns, projectDir, pageExtensions)\n} catch (err) {\n  if (err.message.startsWith('Failed to resolve pattern')) {\n    // log pattern, fall back to default file discovery\n  }\n  throw err\n}","preventionTips":["Validate glob patterns with a standalone glob call before passing to resolveBuildPaths.","Keep dynamic-route segments well-formed so escapeBrackets can process them.","Avoid hand-building brace-expanded combined patterns; pass individual patterns to the API."],"tags":["build","glob","routing","config"],"analyzedSha":"0ae8c72462952df163f1b1e0726641bc5b40dc93","analyzedAt":"2026-08-06T19:44:29.143Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}