{"record":{"id":"26c1496d6578e167","repo":"vercel/next.js","slug":"invalid-urlpath-provided-to-revalidate-must-be","errorCode":null,"errorMessage":"Invalid urlPath provided to revalidate(), must be a path e.g. /blog/post-1, received ${urlPath}","messagePattern":"Invalid urlPath provided to revalidate\\(\\), must be a path e\\.g\\. /blog/post-1, received (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/next/src/server/api-utils/node/api-resolver.ts","lineNumber":257,"sourceCode":"        : undefined),\n      ...(options.path !== undefined\n        ? ({ path: options.path } as CookieSerializeOptions)\n        : undefined),\n    }),\n  ])\n  return res\n}\n\nasync function revalidate(\n  urlPath: string,\n  opts: {\n    unstable_onlyGenerated?: boolean\n  },\n  req: IncomingMessage,\n  context: ApiContext\n) {\n  if (typeof urlPath !== 'string' || !urlPath.startsWith('/')) {\n    throw new Error(\n      `Invalid urlPath provided to revalidate(), must be a path e.g. /blog/post-1, received ${urlPath}`\n    )\n  }\n  const headers: HeadersInit = {\n    [PRERENDER_REVALIDATE_HEADER]: context.previewModeId,\n    ...(opts.unstable_onlyGenerated\n      ? {\n          [PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER]: '1',\n        }\n      : {}),\n  }\n  const allowedRevalidateHeaderKeys = [\n    ...(context.allowedRevalidateHeaderKeys || []),\n  ]\n\n  if (context.trustHostHeader || context.dev) {\n    allowedRevalidateHeaderKeys.push('cookie')\n  }","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/vercel/next.js/blob/0ae8c72462952df163f1b1e0726641bc5b40dc93/packages/next/src/server/api-utils/node/api-resolver.ts#L239-L275","documentation":"Thrown by the internal revalidate() function (wired to res.revalidate) when urlPath is not a string or does not start with '/'. On-demand revalidation requires an absolute site path (e.g. /blog/post-1) so Next.js can locate and purge the correct cached route; a relative or malformed path cannot be resolved.","triggerScenarios":"Calling res.revalidate('blog/post-1') (missing leading slash), res.revalidate('https://example.com/blog') (a full URL), res.revalidate('') , or res.revalidate(undefined). The check `typeof urlPath !== 'string' || !urlPath.startsWith('/')` fails.","commonSituations":"Passing a full URL instead of a path; building the path from user input without normalizing; forgetting the leading slash after refactoring route helpers.","solutions":["Pass a site-relative path starting with '/', e.g. res.revalidate('/blog/post-1').","Strip the origin from full URLs before revalidating: new URL(input).pathname.","Validate/coerce the input to a string and prepend '/' if missing."],"exampleFix":"// before\nres.revalidate('blog/post-1')\nres.revalidate('https://site.com/blog/post-1')\n// after\nres.revalidate('/blog/post-1')\nres.revalidate(new URL(input).pathname)","handlingStrategy":"validation","validationCode":"function normalizeRevalidatePath(urlPath: unknown): string {\n  if (typeof urlPath !== 'string') throw new Error('urlPath must be a string')\n  if (urlPath.startsWith('http')) {\n    try { urlPath = new URL(urlPath).pathname } catch { /* fall through */ }\n  }\n  if (!urlPath.startsWith('/')) urlPath = '/' + urlPath\n  return urlPath\n}","typeGuard":"function isRevalidatablePath(p: unknown): p is string {\n  return typeof p === 'string' && p.startsWith('/')\n}","tryCatchPattern":null,"preventionTips":["Always pass a path starting with '/' to res.revalidate().","Convert full URLs to pathnames via new URL(input).pathname.","Validate user-supplied paths before revalidating."],"tags":["api-routes","revalidation","cache","runtime","validation"],"analyzedSha":"0ae8c72462952df163f1b1e0726641bc5b40dc93","analyzedAt":"2026-08-06T19:44:29.143Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}