argoproj/argo-workflows · warning

Invalid path. Expected: /upload-artifacts/

Error message

Invalid path. Expected: /upload-artifacts/{namespace}/{workflowTemplateName}/{artifactName}

What it means

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.

Solutions

  1. Include all three path parameters: /upload-artifacts/{namespace}/{workflowTemplateName}/{artifactName}
  2. Print/verify the final URL after any proxy rewriting
  3. Ensure no component strips or collapses path segments (e.g. ingress rewrite rules)

Example fix

// before
const url = `/upload-artifacts/${ns}/${templateName}`;
// after
if (!artifactName) throw new Error("artifactName required");
const url = `/upload-artifacts/${ns}/${templateName}/${artifactName}`;
Defensive patterns

Strategy: validation

Validate before calling

const parts = new URL(url).pathname.split('/').filter(Boolean);
if (parts.length !== 4 || parts[0] !== 'upload-artifacts') {
  throw new Error(`Invalid path, expected /upload-artifacts/{ns}/{template}/{artifact}, got ${url}`);
}

Prevention

When it happens

Trigger: 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.

Common situations: Hand-built URLs missing the artifact name, trailing-slash confusion, proxy path trimming, client templates with unfilled placeholders (empty segments).

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/22b52c178699660a. Report an issue: GitHub.

Appendix: source

Thrown at server/artifacts/artifact_server.go:91

}

// UploadInputArtifact handles file uploads for workflow input artifacts
// Path: /upload-artifacts/{namespace}/{workflowTemplateName}/{artifactName}
// Method: POST
// Body: multipart/form-data with "file" field
// Response: JSON with artifact location information
//
//nolint:contextcheck
func (a *ArtifactServer) UploadInputArtifact(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// Parse path: /upload-artifacts/{namespace}/{workflowTemplateName}/{artifactName}
	requestPath := strings.SplitN(r.URL.Path, "/", 5)
	if len(requestPath) < 5 {
		http.Error(w, "Invalid path. Expected: /upload-artifacts/{namespace}/{workflowTemplateName}/{artifactName}", http.StatusBadRequest)
		return
	}
	namespace := requestPath[2]
	workflowTemplateName := requestPath[3]
	artifactName := requestPath[4]

	// Authenticate and authorize
	ctx, err := a.gateKeeping(r, types.NamespaceHolder(namespace))
	if err != nil {
		a.unauthorizedError(w)
		return
	}

	a.logger.WithFields(logging.Fields{
		"namespace":            namespace,
		"workflowTemplateName": workflowTemplateName,
		"artifactName":         artifactName,
	}).Info(ctx, "Upload artifact")

View on GitHub (pinned to 35bff19146)