{"record":{"id":"e6530b465379c150","repo":"argoproj/argo-workflows","slug":"artifact-key-q-must-have-a-valid-uuid-segment-w","errorCode":null,"errorMessage":"artifact key %q must have a valid UUID segment: %w","messagePattern":"artifact key %q must have a valid UUID segment: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/utils/artifactkey.go","lineNumber":45,"sourceCode":"\t}\n\tif strings.HasPrefix(key, \"/\") {\n\t\treturn fmt.Errorf(\"artifact key %q must not be an absolute path\", key)\n\t}\n\tif path.Clean(key) != key {\n\t\treturn fmt.Errorf(\"artifact key %q is not in canonical form\", key)\n\t}\n\n\tparts := strings.Split(key, \"/\")\n\tif len(parts) != 4 {\n\t\treturn fmt.Errorf(\"artifact key %q must have exactly 4 segments: uploads/{namespace}/{uuid}/{filename}\", key)\n\t}\n\tif slices.Contains(parts, \"\") {\n\t\treturn fmt.Errorf(\"artifact key %q must not contain empty segments\", key)\n\t}\n\n\tuuidSegment := parts[2]\n\tif _, err := uuid.Parse(uuidSegment); err != nil {\n\t\treturn fmt.Errorf(\"artifact key %q must have a valid UUID segment: %w\", key, err)\n\t}\n\n\tfilename := parts[3]\n\tif path.Base(filename) != filename {\n\t\treturn fmt.Errorf(\"artifact key %q must have a bare filename segment\", key)\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":27,"sourceCodeEnd":55,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/server/utils/artifactkey.go#L27-L55","documentation":"ValidateUploadedArtifactKey validates that a client-supplied artifact key exactly matches the upload-endpoint format uploads/{namespace}/{uuid}/{filename}. The third segment must parse as a UUID (github.com/google/uuid.Parse). This check exists because the key is applied to the artifact location without further verification, so malformed segments could otherwise enable path manipulation or key confusion.","triggerScenarios":"Calling ValidateUploadedArtifactKey with a key whose 3rd '/'-separated segment (parts[2]) is not a parseable UUID — e.g. 'uploads/myns/not-a-uuid/file.txt', 'uploads/myns/12345/file.txt', or 'uploads/myns//file.txt' shaped so the uuid slot holds arbitrary text.","commonSituations":"Hand-constructing artifact keys instead of using the ones the upload endpoint generated; copying a key and truncating/altering the UUID; tools that build keys from workflow/step names instead of the server-generated UUID; version drift where older clients produced keys without the UUID segment.","solutions":["Use the exact key string returned by the artifact upload endpoint rather than constructing it by hand.","Verify the key has exactly 4 segments and that segment index 2 is a valid UUID: run uuid.Parse on it client-side before sending.","If you have only the filename, re-request a fresh upload slot from the server so a correct UUID is generated."],"exampleFix":"// before\nkey := \"uploads/myns/step-1-output/results.tgz\"\n// after\nkey := fmt.Sprintf(\"uploads/%s/%s/%s\", namespace, uuid.NewString(), \"results.tgz\")","handlingStrategy":"validation","validationCode":"func looksLikeUploadKey(namespace, key string) bool {\n    parts := strings.Split(key, \"/\")\n    return len(parts) == 4 && parts[0] == \"uploads\" && parts[1] == namespace &&\n        func() bool { _, err := uuid.Parse(parts[2]); return err == nil }()\n}","typeGuard":"func isValidUUID(s string) bool { _, err := uuid.Parse(s); return err == nil }","tryCatchPattern":"if err := utils.ValidateUploadedArtifactKey(ns, key); err != nil {\n    var uerr *uuid.Error\n    if errors.As(err, &uerr) {\n        return fmt.Errorf(\"regenerate upload key: UUID segment invalid: %w\", err)\n    }\n    return err\n}","preventionTips":["Always take the key verbatim from the upload endpoint response, never assemble it manually.","Keep a client-side helper that formats keys as uploads/{ns}/{uuid}/{filename} so the format lives in one place.","Validate keys with uuid.Parse before any upload/download call."],"tags":["go","validation","artifacts"],"backgroundTag":"invalid-artifact-key","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"}