{"record":{"id":"19cef932642c1a33","repo":"angular/angular-cli","slug":"invalid-frompath-the-string-must-start-with-a","errorCode":null,"errorMessage":"Invalid fromPath: The string must start with a '/'. Received: '${fromPath}'","messagePattern":"Invalid fromPath: The string must start with a '/'\\. Received: '(.+?)'","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/angular/ssr/src/utils/url.ts","lineNumber":190,"sourceCode":" *\n * @example\n * ```typescript\n * // Example with placeholders resolved\n * const resolvedPath = buildPathWithParams('/*\\/details', '/123/abc');\n * console.log(resolvedPath); // Outputs: '/123/details'\n *\n * // Example with a static path\n * const staticPath = buildPathWithParams('/static/path', '/base/unused');\n * console.log(staticPath); // Outputs: '/static/path'\n * ```\n */\nexport function buildPathWithParams(toPath: string, fromPath: string): string {\n  if (toPath[0] !== '/') {\n    throw new Error(`Invalid toPath: The string must start with a '/'. Received: '${toPath}'`);\n  }\n\n  if (fromPath[0] !== '/') {\n    throw new Error(`Invalid fromPath: The string must start with a '/'. Received: '${fromPath}'`);\n  }\n\n  if (!toPath.includes('/*')) {\n    return toPath;\n  }\n\n  const fromPathParts = fromPath.split('/');\n  const toPathParts = toPath.split('/');\n  const resolvedParts = toPathParts.map((part, index) =>\n    toPathParts[index] === '*' ? fromPathParts[index] : part,\n  );\n\n  return joinUrlParts(...resolvedParts);\n}\n\nconst MATRIX_PARAMS_REGEX = /;[^/]+/g;\n\n/**","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular/ssr/src/utils/url.ts#L172-L208","documentation":"This is the second check in buildPathWithParams: the source path (fromPath) must also be a root-relative absolute path starting with '/'. fromPath supplies the parameter values that get merged into the destination path, so a relative source cannot be interpreted.","triggerScenarios":"Calling buildPathWithParams('/static/path', 'base/unused') or any fromPath without a leading slash (empty string, 'foo', './foo').","commonSituations":"Passing a route param segment like 'users/:id' directly; accidentally passing only the tail of a URL after splitting on '/'; server-base or deploy-url config missing its leading slash.","solutions":["Ensure fromPath starts with '/': normalize with ('/' + fromPath.replace(/^\\/+/, '')).","Check you are passing the full request/config URL to fromPath, not a split remainder.","Validate both inputs with startsWith('/') before the call."],"exampleFix":"// before\nbuildPathWithParams('/static/path', 'users/42');\n// after\nbuildPathWithParams('/static/path', '/users/42');","handlingStrategy":"validation","validationCode":"if (!fromPath.startsWith('/')) {\n  throw new TypeError(`fromPath must be absolute: got '${fromPath}'`);\n}\nbuildPathWithParams(toPath, fromPath);","typeGuard":"function isRootRelative(p: unknown): p is string {\n  return typeof p === 'string' && p.startsWith('/');\n}","tryCatchPattern":"try {\n  return buildPathWithParams(toPath, fromPath);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Invalid fromPath:')) {\n    return buildPathWithParams(toPath, '/' + fromPath.replace(/^\\/+/, ''));\n  } throw e;\n}","preventionTips":["Pass the full URL pathname (e.g. new URL(req.url).pathname) as fromPath, never a split remainder.","Never pass route parameter fragments like ':id' as the source path.","Add a unit test asserting both inputs start with '/'."],"tags":["angular","ssr","path-validation","argument-error"],"backgroundTag":"path-must-be-absolute","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}