argoproj/argo-workflows · error

artifact %s failed to load: %w

Error message

artifact %s failed to load: %w

What it means

After creating the temp dir, the executor calls artDriver.Load to fetch the artifact into the temp path. Any non-recoverable driver error is wrapped as 'artifact <name> failed to load: <cause>'. Optional artifacts whose error is CodeNotFound are silently skipped instead.

Source

Thrown at workflow/executor/executor.go:338

	// The artifact is downloaded to a temporary location, after which we determine if
	// the file is a tarball or not. If it is, it is first extracted then renamed to
	// the desired location. If not, it is simply renamed to the location.
	tempArtPath := artPath + ".tmp"
	// Ensure parent directory exist, create if missing
	tempArtDir := filepath.Dir(tempArtPath)
	if mkdirErr := os.MkdirAll(tempArtDir, 0o700); mkdirErr != nil {
		return fmt.Errorf("failed to create artifact temporary parent directory %s: %w", tempArtDir, mkdirErr)
	}
	ctx, span := we.Tracing.StartLoadArtifact(ctx, artPath)
	defer span.End()
	err = artDriver.Load(ctx, driverArt, tempArtPath)
	if err != nil {
		if art.Optional && argoerrs.IsCode(argoerrs.CodeNotFound, err) {
			logger.WithField("name", art.Name).Info(ctx, "Skipping optional input artifact that was not found")
			return nil
		}
		return fmt.Errorf("artifact %s failed to load: %w", art.Name, err)
	}

	err = we.unarchiveArtifact(ctx, art, tempArtPath, artPath)
	if err != nil {
		return err
	}

	logger.WithField("path", artPath).Info(ctx, "Successfully download file")
	if art.Mode != nil {
		err = chmod(artPath, *art.Mode, art.RecurseMode)
		if err != nil {
			return err
		}
	} else if driverArt.Plugin != nil {
		// For plugin artifacts without explicit mode, ensure the file is writable
		// by setting mode to 0666 so the main container can read/write it
		err = chmod(artPath, 0666, art.RecurseMode)
		if err != nil {

View on GitHub (pinned to 35bff19146)

Solutions

  1. Read the wrapped cause to identify the driver-level failure (404, auth, network)
  2. Mark the artifact optional: true if the producer may legitimately skip it
  3. Verify the artifact's bucket/key and the artifact-repository credentials/secret
  4. Check pod network egress and the storage backend's availability

Example fix

# before
artifacts:
  - name: maybe-data
    path: /mnt/data
    s3:
      key: outputs/maybe.json
# after
artifacts:
  - name: maybe-data
    path: /mnt/data
    optional: true
    s3:
      key: outputs/maybe.json
Defensive patterns

Strategy: validation

Validate before calling

# Verify the object exists and credentials work before running:
# aws s3 ls s3://my-bucket/outputs/maybe.json --region <region>
# Mark artifacts optional when the producer may skip them:
# artifacts:
#   - name: maybe-data
#     optional: true

Try / catch

if err := loadArtifacts(ctx); err != nil {
	if strings.Contains(err.Error(), "failed to load") {
		// inspect wrapped cause: 404 -> mark optional or fix key;
		// 401/403 -> fix credentials; timeout -> retry
	}
}

Prevention

When it happens

Trigger: The storage driver (s3/gcs/azure/oss/http/git/raw/...) fails to download the artifact: object does not exist (and artifact not optional), bad credentials, network failure, wrong bucket/key, or a driver misconfiguration.

Common situations: Upstream step did not produce the output artifact but it isn't marked optional; expired/missing storage credentials; key renamed or bucket region wrong; network egress blocked from the pod; artifact deleted by retention policy.

Related errors


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