{"record":{"id":"9b145f8709dea8a7","repo":"argoproj/argo-workflows","slug":"error-appending-filename-s-to-key-of-artifact-v","errorCode":null,"errorMessage":"error appending filename %s to key of artifact %+v: err: %w","messagePattern":"error appending filename (.+?) to key of artifact %\\+v: err: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/artifacts/artifact_server.go","lineNumber":729,"sourceCode":"\t\tarchiveLocation = template.ArchiveLocation // this is case 4\n\t}\n\n\tif templateName == \"\" || !archiveLocation.HasLocation() {\n\t\tar, arErr := a.artifactRepositories.Get(ctx, wf.Status.ArtifactRepositoryRef) // this should handle cases 2, 3 and 5\n\t\tif arErr != nil {\n\t\t\treturn art, nil, arErr\n\t\t}\n\t\tarchiveLocation = ar.ToArtifactLocation()\n\t}\n\n\terr = art.Relocate(archiveLocation) // if the Artifact defines the location (case 1), it will be used; otherwise whatever archiveLocation is set to\n\tif err != nil {\n\t\treturn art, nil, err\n\t}\n\tif fileName != nil {\n\t\terr = art.AppendToKey(*fileName)\n\t\tif err != nil {\n\t\t\treturn art, nil, fmt.Errorf(\"error appending filename %s to key of artifact %+v: err: %w\", *fileName, art, err)\n\t\t}\n\t\tlogger.WithFields(logging.Fields{\n\t\t\t\"fileName\": *fileName,\n\t\t\t\"artifact\": art,\n\t\t}).Debug(ctx, \"appended key to artifact\")\n\t}\n\n\tdriver, err := a.artDriverFactory(ctx, art, resources{kubeClient, wf.Namespace})\n\tif err != nil {\n\t\treturn art, nil, err\n\t}\n\tlogger.WithFields(logging.Fields{\n\t\t\"artifact\": art,\n\t}).Debug(ctx, \"successfully located driver associated with artifact\")\n\n\treturn art, driver, nil\n}\n","sourceCodeStart":711,"sourceCodeEnd":747,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/server/artifacts/artifact_server.go#L711-L747","documentation":"When serving an artifact file the server can append a requested file name to the artifact's storage key (e.g. for log files or sub-paths). art.AppendToKey calls ArtifactLocation.GetKey(); if the artifact/location has no key or an unsupported/invalid location type, GetKey errors and the server wraps it as 'error appending filename <name> to key of artifact ...'. It means the artifact's resolved location has no usable key path to append to.","triggerScenarios":"Calling GetArtifactFile with a fileName (log download, `argo logs --artifact`, artifact sub-path request) for an artifact whose resolved ArtifactLocation has no key: e.g. artifact location is an empty/non-existent output, location key is unset because the step failed before producing the artifact, or the location type doesn't support GetKey (e.g. raw/inline or an artifact that only got a default repo with no key).","commonSituations":"Downloading logs of a failed/pending pod that never wrote its log artifact; requesting a sub-file from an artifact whose storage backend was misconfigured (empty key in artifact repository configmap); artifacts relocated from an archive location where the key portion is missing; using s3/git drivers with a key-less artifact spec.","solutions":["Check the node's outputs: `argo get <wf> -o json | jq '.status.nodes[\"<nodeID>\"].outputs'` — confirm the artifact exists and has a non-empty s3.key (or equivalent).","Only request fileName/log downloads for completed nodes whose artifacts were actually produced; for pod logs use `argo logs <pod>` on a successful step.","Fix the artifact repository configmap (workflow-controller-configmap artifactRepository s3.key format) if keys are being generated empty.","Verify the workflow step succeeded — failed steps often have no artifact key; retry the step first.","Inspect the artifact spec in your template: ensure the output artifact has a path and the location type supports keys (s3/gcs/azure/oss), not raw/inline."],"exampleFix":"// before: requesting artifact file sub-path from a possibly-keyless artifact\nf, err := svc.GetArtifactFile(ctx, nodeID, artName, isInput, &fileName) // panics on empty key\n// after: verify the artifact has a key first\nwf, _ := wfClient.ArgoprojV1alpha1().Workflows(ns).Get(ctx, wfName, metav1.GetOptions{})\nnode := wf.Status.Nodes[nodeID]\nart := node.Outputs.GetArtifactByName(artName)\nif art == nil || !art.HasLocation() {\n    return fmt.Errorf(\"artifact %s on node %s has no stored location; step may have failed\", artName, nodeID)\n}\nf, err := svc.GetArtifactFile(ctx, nodeID, artName, isInput, &fileName)","handlingStrategy":"validation","validationCode":"node, ok := wf.Status.Nodes[nodeID]\nif !ok || node.Phase != wfv1.NodeSucceeded {\n    return fmt.Errorf(\"node %s not succeeded; artifact key may not exist\", nodeID)\n}\nart := node.Outputs.GetArtifactByName(artifactName)\nif art == nil || !art.HasLocation() {\n    return fmt.Errorf(\"artifact %q has no stored location/key\", artifactName)\n}","typeGuard":"func artifactHasKey(node wfv1.NodeStatus, name string, isInput bool) bool {\n    var art *wfv1.Artifact\n    if isInput { art = node.Inputs.GetArtifactByName(name) } else { art = node.Outputs.GetArtifactByName(name) }\n    return art != nil && art.HasLocation()\n}","tryCatchPattern":"f, err := svc.GetArtifactFile(ctx, nodeID, artName, isInput, &fileName)\nif err != nil {\n    var appendErr string = \"error appending filename\"\n    if strings.Contains(err.Error(), appendErr) {\n        return fmt.Errorf(\"artifact has no key (step may not have run/completed): %w\", err)\n    }\n    return err\n}","preventionTips":["Only request artifact files/sub-paths for nodes in Succeeded phase.","Ensure artifactRepository s3.key format in the controller configmap is correct so generated keys are never empty.","For pod logs, use the log API rather than artifact files for non-completed steps.","Prefer output artifacts with explicit paths in templates."],"tags":["argo-workflows","artifacts","storage","s3"],"backgroundTag":"artifact-key-missing","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"}