{"record":{"id":"22b52c178699660a","repo":"argoproj/argo-workflows","slug":"invalid-path-expected-upload-artifacts-namespa","errorCode":null,"errorMessage":"Invalid path. Expected: /upload-artifacts/{namespace}/{workflowTemplateName}/{artifactName}","messagePattern":"Invalid path\\. Expected: /upload-artifacts/(.+?)/(.+?)/(.+?)","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"server/artifacts/artifact_server.go","lineNumber":91,"sourceCode":"}\n\n// UploadInputArtifact handles file uploads for workflow input artifacts\n// Path: /upload-artifacts/{namespace}/{workflowTemplateName}/{artifactName}\n// Method: POST\n// Body: multipart/form-data with \"file\" field\n// Response: JSON with artifact location information\n//\n//nolint:contextcheck\nfunc (a *ArtifactServer) UploadInputArtifact(w http.ResponseWriter, r *http.Request) {\n\tif r.Method != http.MethodPost {\n\t\thttp.Error(w, \"Method not allowed\", http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\n\t// Parse path: /upload-artifacts/{namespace}/{workflowTemplateName}/{artifactName}\n\trequestPath := strings.SplitN(r.URL.Path, \"/\", 5)\n\tif len(requestPath) < 5 {\n\t\thttp.Error(w, \"Invalid path. Expected: /upload-artifacts/{namespace}/{workflowTemplateName}/{artifactName}\", http.StatusBadRequest)\n\t\treturn\n\t}\n\tnamespace := requestPath[2]\n\tworkflowTemplateName := requestPath[3]\n\tartifactName := requestPath[4]\n\n\t// Authenticate and authorize\n\tctx, err := a.gateKeeping(r, types.NamespaceHolder(namespace))\n\tif err != nil {\n\t\ta.unauthorizedError(w)\n\t\treturn\n\t}\n\n\ta.logger.WithFields(logging.Fields{\n\t\t\"namespace\":            namespace,\n\t\t\"workflowTemplateName\": workflowTemplateName,\n\t\t\"artifactName\":         artifactName,\n\t}).Info(ctx, \"Upload artifact\")","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/server/artifacts/artifact_server.go#L73-L109","documentation":"The handler parses r.URL.Path with strings.SplitN(path, \"/\", 5) and requires at least 5 segments so that namespace, workflowTemplateName and artifactName are all present. If the path has fewer segments, it responds 400 with the expected path shape.","triggerScenarios":"Calling /upload-artifacts, /upload-artifacts/default, or /upload-artifacts/default/my-tmpl (missing artifactName); a URL-encoding or reverse-proxy rewrite stripping trailing path segments; double slashes collapsing segments.","commonSituations":"Hand-built URLs missing the artifact name, trailing-slash confusion, proxy path trimming, client templates with unfilled placeholders (empty segments).","solutions":["Include all three path parameters: /upload-artifacts/{namespace}/{workflowTemplateName}/{artifactName}","Print/verify the final URL after any proxy rewriting","Ensure no component strips or collapses path segments (e.g. ingress rewrite rules)"],"exampleFix":"// before\nconst url = `/upload-artifacts/${ns}/${templateName}`;\n// after\nif (!artifactName) throw new Error(\"artifactName required\");\nconst url = `/upload-artifacts/${ns}/${templateName}/${artifactName}`;","handlingStrategy":"validation","validationCode":"const parts = new URL(url).pathname.split('/').filter(Boolean);\nif (parts.length !== 4 || parts[0] !== 'upload-artifacts') {\n  throw new Error(`Invalid path, expected /upload-artifacts/{ns}/{template}/{artifact}, got ${url}`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build URLs from a helper that takes namespace, template, artifactName explicitly","Assert no path component is empty before formatting","Watch for proxies that rewrite/strip path prefixes"],"tags":["http","http-400","url-path","rest"],"backgroundTag":"invalid-request-path","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}