{"record":{"id":"ddac79f995ce96d0","repo":"microsoft/aspire","slug":"the-apipath-must-start-with","errorCode":null,"errorMessage":"The apiPath must start with '/'.","messagePattern":"The apiPath must start with '/'\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs","lineNumber":1303,"sourceCode":"    {\n        ArgumentNullException.ThrowIfNull(builder);\n        ArgumentException.ThrowIfNullOrEmpty(options.OutputPath);\n\n        if (apiPath is not null && apiTarget is null)\n        {\n            throw new ArgumentException(\"apiTarget is required when apiPath is specified.\", nameof(apiTarget));\n        }\n\n        if (apiTarget is not null && apiPath is null)\n        {\n            throw new ArgumentException(\"apiPath is required when apiTarget is specified.\", nameof(apiPath));\n        }\n\n        if (apiPath is not null && apiTarget is not null)\n        {\n            if (!apiPath.StartsWith('/'))\n            {\n                throw new ArgumentException(\"The apiPath must start with '/'.\", nameof(apiPath));\n            }\n\n            apiPath = apiPath.TrimEnd('/');\n\n            if (apiPath.Length == 0)\n            {\n                throw new ArgumentException(\"The apiPath must not be '/' — it would match all requests and make the static site unreachable.\", nameof(apiPath));\n            }\n\n            ValidateApiPath(apiPath);\n            builder.WithReference(apiTarget);\n        }\n\n        if (!builder.ApplicationBuilder.ExecutionContext.IsPublishMode)\n        {\n            return builder;\n        }\n","sourceCodeStart":1285,"sourceCodeEnd":1321,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs#L1285-L1321","documentation":"The apiPath for the API proxy must be an absolute route beginning with '/'. Aspire normalizes the path (trimming trailing slashes) and mounts it in the dev-server proxy, which relies on the leading slash; a relative value like \"api\" would produce an invalid or unintended route.","triggerScenarios":"Calling the API-proxy extension with apiPath: \"api\" (no leading slash), often a value read from configuration or built by string concatenation.","commonSituations":"Paths loaded from appsettings/environment variables that lack the leading slash; concatenation like $\"{basePath}/api\" where basePath is empty; users used to relative route registration APIs.","solutions":["Prefix the value with '/' before passing it, e.g. apiPath: \"/api\".","Normalize at the call site: if (!path.StartsWith('/')) path = \"/\" + path.","Validate/normalize configurable path values when loading settings."],"exampleFix":"// before\n.WithApiProxy(apiPath: \"api\", apiTarget: apiBuilder);\n// after\n.WithApiProxy(apiPath: \"/api\", apiTarget: apiBuilder);","handlingStrategy":"validation","validationCode":"if (apiPath is not null && !apiPath.StartsWith('/'))\n    apiPath = \"/\" + apiPath;","typeGuard":"bool IsAbsoluteRoutePath(string? p) => p is not null && p.StartsWith('/');","tryCatchPattern":null,"preventionTips":["Validate configurable path values include a leading slash at load time.","Avoid building route paths by raw string concatenation.","Normalize paths in one shared helper before passing to Aspire APIs."],"tags":["aspire","javascript","argument-validation","url-format"],"backgroundTag":"invalid-argument-format","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"}