{"record":{"id":"57d36253d2b11853","repo":"argoproj/argo-workflows","slug":"artifact-s-does-not-have-a-storage-location-con","errorCode":null,"errorMessage":"Artifact '%s' does not have a storage location configured (s3, gcs, azure, oss). Please configure a storage location in the WorkflowTemplate or set up a default artifact repository.","messagePattern":"Artifact '(.+?)' does not have a storage location configured \\(s3, gcs, azure, oss\\)\\. Please configure a storage location in the WorkflowTemplate or set up a default artifact repository\\.","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"server/artifacts/artifact_server.go","lineNumber":224,"sourceCode":"\t// 2. Namespace has artifact-repositories ConfigMap\n\t// 3. workflow-controller-configmap has default artifactRepository\n\t// We don't use Relocate() because it requires an existing key, but for uploads we generate a new key anyway.\n\tif !artifactCopy.HasLocation() {\n\t\tarchiveLocation, resolveErr := sutils.ResolveArtifactLocation(ctx, a.artifactRepositories, wfTemplate.Spec.ArtifactRepositoryRef, namespace)\n\t\tif resolveErr != nil {\n\t\t\ta.logger.WithError(resolveErr).Debug(ctx, \"Failed to resolve artifact repository, will check if artifact has location anyway\")\n\t\t} else if archiveLocation != nil && archiveLocation.HasLocation() {\n\t\t\t// Copy the location settings (bucket, endpoint, etc.) to our artifact\n\t\t\tartifactCopy.ArtifactLocation = *archiveLocation.DeepCopy()\n\t\t\ta.logger.WithFields(logging.Fields{\n\t\t\t\t\"artifactName\": artifactName,\n\t\t\t}).Info(ctx, \"Resolved artifact location from default repository\")\n\t\t}\n\t}\n\n\t// Check if the artifact has a location configured (S3, GCS, etc.)\n\tif !artifactCopy.HasLocation() {\n\t\thttp.Error(w, fmt.Sprintf(\"Artifact '%s' does not have a storage location configured (s3, gcs, azure, oss). Please configure a storage location in the WorkflowTemplate or set up a default artifact repository.\", artifactName), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// Generate unique key for the artifact\n\tuploadUUID := uuid.NewString()\n\toriginalKey, _ := artifactCopy.GetKey()\n\t// Sanitize filename to prevent path traversal attacks. path.Base only\n\t// recognises '/' as a separator, so normalise Windows-style '\\' first.\n\tsanitizedFilename := path.Base(strings.ReplaceAll(header.Filename, \"\\\\\", \"/\"))\n\tif sanitizedFilename == \".\" || sanitizedFilename == \"/\" || sanitizedFilename == \"\" {\n\t\thttp.Error(w, \"Invalid filename\", http.StatusBadRequest)\n\t\treturn\n\t}\n\t// Replace the key with uploaded file path under uploads/\n\tnewKey := fmt.Sprintf(\"uploads/%s/%s/%s\", namespace, uploadUUID, sanitizedFilename)\n\tif validateErr := sutils.ValidateUploadedArtifactKey(namespace, newKey); validateErr != nil {\n\t\ta.serverInternalError(ctx, fmt.Errorf(\"generated artifact key failed self-validation: %w\", validateErr), w)\n\t\treturn","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/server/artifacts/artifact_server.go#L206-L242","documentation":"After resolving the artifact and attempting to fill in the location from the default artifact repository, UploadInputArtifact checks artifactCopy.HasLocation(). If neither the artifact itself nor any configured default (artifactRepositoryRef, namespace artifact-repositories ConfigMap, or workflow-controller-configmap default artifactRepository) provides an s3/gcs/azure/oss location, the upload is rejected with HTTP 400 because there is nowhere to store the file.","triggerScenarios":"The artifact in spec.arguments.artifacts has no s3/gcs/azure/oss block; no artifactRepositoryRef on the template; no artifact-repositories ConfigMap in the namespace; workflow-controller-configmap has no default artifactRepository configured; ResolveArtifactLocation failed (logged at debug) so the fallback location was never applied.","commonSituations":"Fresh Argo installs without artifact storage configured in the controller configmap; users assuming artifact uploads work without any artifact repository; namespace-level artifact-repositories ConfigMap misnamed or missing; template copied from an example that uses raw/passthrough artifacts with no location.","solutions":["Configure a default artifactRepository in the workflow-controller-configmap (e.g. an s3 block).","Add a storage backend (s3/gcs/azure/oss) directly to the artifact in the WorkflowTemplate's arguments.artifacts.","Set spec.artifactRepositoryRef on the WorkflowTemplate or create an artifact-repositories ConfigMap in the namespace.","Check controller logs at debug level for the 'Failed to resolve artifact repository' message to see why the default could not be applied."],"exampleFix":"// before\nartifacts:\n  - name: data\n// after\nartifacts:\n  - name: data\n    s3:\n      bucket: my-bucket\n      key: path/in/bucket","handlingStrategy":"validation","validationCode":"# Ensure a default artifact repository or explicit location exists before upload\nkubectl -n argo get cm workflow-controller-configmap -o yaml | grep -A3 artifactRepository\nkubectl -n $NS get cm artifact-repositories 2>/dev/null || echo 'no namespace artifact-repositories ConfigMap'","typeGuard":null,"tryCatchPattern":"if (!artifact.s3 && !artifact.gcs && !artifact.azure && !artifact.oss && !defaultRepoConfigured) {\n  throw new Error(`artifact '${artifact.name}' needs a storage location or default artifact repository`);\n}","preventionTips":["Configure the default artifactRepository in workflow-controller-configmap at install time.","Give every uploaded artifact an explicit s3/gcs/azure/oss block in spec.arguments.artifacts.","Run 'argo lint' which surfaces artifacts lacking a resolvable location.","After controller config changes, confirm the configmap mounted in the controller actually updated."],"tags":["configuration","artifact-repository","s3","artifacts"],"backgroundTag":"missing-artifact-storage-configuration","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"}