{"record":{"id":"fbc98a07983a4bad","repo":"microsoft/aspire","slug":"the-path-must-be-a-relative-path","errorCode":null,"errorMessage":"The path must be a relative path.","messagePattern":"The path must be a relative path\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs","lineNumber":3240,"sourceCode":"            }\n            current = parent;\n        }\n\n        return null;\n    }\n\n    private static string NormalizeRelativePath(string path)\n    {\n        var normalizedPath = path.Replace('\\\\', '/');\n\n        if (normalizedPath.StartsWith(\"./\", StringComparison.Ordinal))\n        {\n            normalizedPath = normalizedPath[2..];\n        }\n\n        if (normalizedPath.StartsWith('/'))\n        {\n            throw new ArgumentException(\"The path must be a relative path.\", nameof(path));\n        }\n\n        // Reject path traversal segments. These are virtual Docker container paths (not host\n        // filesystem paths), so Path.GetFullPath cannot be used — it produces platform-specific\n        // results (e.g. D:\\app\\dist on Windows). Segment-based validation works correctly\n        // cross-platform for container paths.\n        var segments = normalizedPath.Split('/', StringSplitOptions.RemoveEmptyEntries);\n        foreach (var segment in segments)\n        {\n            if (segment == \"..\")\n            {\n                throw new ArgumentException(\"The path must not contain \\\"..\\\" segments.\", nameof(path));\n            }\n        }\n\n        return string.Join('/', segments);\n    }\n","sourceCodeStart":3222,"sourceCodeEnd":3258,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs#L3222-L3258","documentation":"This validator normalizes a path destined for the generated Dockerfile (a virtual container path) and requires it to be relative. A path starting with '/' (after optional drive/UNC stripping) cannot be placed under the container's app directory, so it throws an ArgumentException with the path parameter name.","triggerScenarios":"Passing an absolute path such as \"/app/dist\", \"/home/user/out\", or a rooted Windows path that reduces to a leading slash as the path argument to AddNextJsApp-style path options (e.g. publish/dist directory settings).","commonSituations":"Reusing a host filesystem path in a container-path option; concatenating a base directory and forgetting to strip the leading '/'; confusion between host paths and container paths.","solutions":["Pass a relative path without a leading slash, e.g. \"dist\" or \"out/frontend\".","Strip the leading '/' from the computed path before calling the API.","Do not attempt to point container paths at host absolute locations; mount/copy semantics differ."],"exampleFix":"// before\noptions.OutputPath = \"/app/dist\";\n// after\noptions.OutputPath = \"dist\";","handlingStrategy":"validation","validationCode":"static bool IsRelativeContainerPath(string? path) =>\n    !string.IsNullOrEmpty(path) && !path.Replace(\"\\\\\", \"/\").TrimStart().StartsWith('/');","typeGuard":"bool IsRelativeContainerPath(string? path) => !string.IsNullOrEmpty(path) && !path.Replace(\"\\\\\", \"/\").TrimStart().StartsWith('/');","tryCatchPattern":"try { options.OutputPath = p; } catch (ArgumentException ex) when (ex.Message.Contains(\"relative path\")) { /* strip leading slash / recompute relative path */ }","preventionTips":["Keep container paths relative to the app directory.","Document that path options are virtual container paths, not host paths.","Normalize with Path.GetRelativePath against the app dir before assignment."],"tags":["javascript","nextjs","docker","path"],"backgroundTag":"invalid-argument-value","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}