argoproj/argo-workflows · warning

Method not allowed

Error message

Method not allowed

What it means

UploadInputArtifact handles multipart artifact uploads at /upload-artifacts/{namespace}/{workflowTemplateName}/{artifactName} and only accepts POST. Any other HTTP verb (GET, PUT, DELETE...) is rejected with 405 "Method not allowed" and the handler returns without processing.

Solutions

  1. Send the request with method POST: curl -X POST -F "file=@my-artifact.txt" <url>
  2. Use curl -F (multipart form) rather than -d, which defaults to POST anyway but ensure verb is POST
  3. Update any client code/health checks to use POST or a different endpoint

Example fix

# before
curl https://argo-server:2746/upload-artifacts/default/my-tmpl/my-artifact
# after
curl -X POST -F "file=@data.bin" https://argo-server:2746/upload-artifacts/default/my-tmpl/my-artifact
Defensive patterns

Strategy: try-catch

Validate before calling

if (method !== 'POST') {
  throw new Error(`upload-artifacts requires POST, got ${method}`);
}

Try / catch

resp, err := http.Post(url, "", body)
if err != nil { return err }
if resp.StatusCode == http.StatusMethodNotAllowed {
    return fmt.Errorf("endpoint requires POST; check client method")
}

Prevention

When it happens

Trigger: Issuing a GET or PUT to the upload-artifacts endpoint instead of a POST multipart/form-data request; curl without -X POST or --upload-file defaults; a proxy/health-checker probing the endpoint with GET.

Common situations: Testing the URL in a browser (GET), scripts reusing a generic HTTP helper that defaults to GET, API gateways that rewrite methods.

Related errors


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

Appendix: source

Thrown at server/artifacts/artifact_server.go:84

func (a *ArtifactServer) GetOutputArtifact(w http.ResponseWriter, r *http.Request) {
	a.getArtifact(w, r, false)
}

//nolint:contextcheck
func (a *ArtifactServer) GetInputArtifact(w http.ResponseWriter, r *http.Request) {
	a.getArtifact(w, r, true)
}

// 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

View on GitHub (pinned to 35bff19146)