argoproj/argo-workflows · error
artifact key %q must not be an absolute path
Error message
artifact key %q must not be an absolute path
What it means
ValidateUploadedArtifactKey rejects keys starting with '/' because keys are object-style relative paths, not filesystem absolute paths. An absolute path would also fail the prefix check, but this rule gives a specific error for clarity.
Source
Thrown at server/utils/artifactkey.go:29
// ValidateUploadedArtifactKey checks that key is exactly the format the upload
// endpoint generates for namespace: uploads/{namespace}/{uuid}/{filename}. It
// rejects path traversal, absolute paths, empty segments, and any key outside
// the upload prefix, since a client-supplied key is otherwise applied to the
// artifact location without further checks.
//
// This is defense-in-depth, not a proof of ownership: a valid-looking key
// naming another user's upload under the same namespace still passes.
func ValidateUploadedArtifactKey(namespace, key string) error {
prefix := "uploads/" + namespace + "/"
if !strings.HasPrefix(key, prefix) {
return fmt.Errorf("artifact key %q must start with %q", key, prefix)
}
if strings.Contains(key, "..") {
return fmt.Errorf("artifact key %q must not contain '..'", key)
}
if strings.HasPrefix(key, "/") {
return fmt.Errorf("artifact key %q must not be an absolute path", key)
}
if path.Clean(key) != key {
return fmt.Errorf("artifact key %q is not in canonical form", key)
}
parts := strings.Split(key, "/")
if len(parts) != 4 {
return fmt.Errorf("artifact key %q must have exactly 4 segments: uploads/{namespace}/{uuid}/{filename}", key)
}
if slices.Contains(parts, "") {
return fmt.Errorf("artifact key %q must not contain empty segments", key)
}
uuidSegment := parts[2]
if _, err := uuid.Parse(uuidSegment); err != nil {
return fmt.Errorf("artifact key %q must have a valid UUID segment: %w", key, err)
}
View on GitHub (pinned to 35bff19146)
Solutions
- Drop the leading slash so the key is relative: uploads/{namespace}/{uuid}/{filename}.
- Use strings.TrimPrefix(key, "/") only if the remainder matches the required prefix.
- Distinguish local file paths from artifact keys in your code.
Example fix
// before key := "/uploads/my-ns/" + id + "/file.bin" // after key := "uploads/my-ns/" + id + "/file.bin"
Defensive patterns
Strategy: validation
Validate before calling
if strings.HasPrefix(key, "/") {
return fmt.Errorf("key %q must be relative", key)
} Type guard
func isRelativeKey(key string) bool { return !strings.HasPrefix(key, "/") } Try / catch
if err := utils.ValidateUploadedArtifactKey(ns, key); err != nil {
if strings.Contains(err.Error(), "absolute path") {
key = strings.TrimPrefix(key, "/")
}
} Prevention
- Keep local file paths and artifact object keys as separate variables.
- Trim leading slashes when converting URL/filesystem paths to object keys.
- Validate keys before submitting them to artifact APIs.
When it happens
Trigger: Passing '/uploads/ns/uuid/file' or an absolute filesystem path like '/tmp/artifact.tar.gz' as the key.
Common situations: Mixing up local file paths with artifact object keys; prefixing with '/' out of habit from filesystem APIs; copying a URL path including the leading slash.
Related errors
- artifact key %q is not in canonical form
- key unsupported: cannot get key for artifact location, becau
- artifact key %q must start with %q
- artifact key %q must not contain '..'
- artifact key %q must have exactly 4 segments: uploads/{names
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/b8e9f94630dd5808.
Report an issue: GitHub.