zitadel/zitadel · error

upload failed: %w

Error message

upload failed: %w

What it means

The actual storage upload (uploader.UploadAsset, which invokes the command layer to persist the asset to S3/GCS/db storage) failed; the handler wraps the underlying storage error as 500 'upload failed'.

Source

Thrown at internal/api/assets/asset.go:200

		}

		resourceOwner := uploader.ResourceOwner(authz.GetInstance(ctx), ctxData)
		objectName, err := uploader.ObjectName(ctxData)
		if err != nil {
			s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError)
			return
		}
		uploadInfo := &command.AssetUpload{
			ResourceOwner: resourceOwner,
			ObjectName:    objectName,
			ContentType:   mimeType.String(),
			ObjectType:    uploader.ObjectType(),
			File:          file,
			Size:          size,
		}
		err = uploader.UploadAsset(ctx, ctxData.OrgID, uploadInfo, s.Commands())
		if err != nil {
			s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %w", err), http.StatusInternalServerError)
			return
		}
	}
}

func DownloadHandleFunc(s AssetsService, downloader Downloader) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		if s.Storage() == nil {
			return
		}
		ctx := r.Context()
		ownerPath := mux.Vars(r)["owner"]
		resourceOwner := downloader.ResourceOwner(ctx, ownerPath)
		path := ""
		if ownerPath != "" {
			splitPath := strings.Split(r.RequestURI, ownerPath+"/")
			if len(splitPath) < 2 {
				s.ErrorHandler()(w, r, fmt.Errorf("invalid request URI format: %v", r.RequestURI), http.StatusNotFound)

View on GitHub (pinned to 13948f2bcd)

Solutions

  1. Inspect server logs for the wrapped inner error from UploadAsset
  2. Verify storage backend config (endpoint, bucket, access keys) and that the bucket exists and is writable
  3. Test database/storage connectivity and re-upload

Example fix

// before
Storage:
  Type: s3
  Endpoint: https://minio.internal:9000
  Bucket: zitadel-assets # bucket does not exist
// after
# create the bucket first, then:
Storage:
  Type: s3
  Endpoint: https://minio.internal:9000
  Bucket: zitadel-assets
  AccessKeyID: <key>
  SecretAccessKey: <secret>
Defensive patterns

Strategy: retry

Validate before calling

// preflight: verify storage backend reachability/credentials before large uploads
await fetch(`${storageHealthEndpoint}`); // or test-list the configured bucket in ops tooling

Try / catch

try {
  await uploadToOrgAssets(orgId, file);
} catch (e) {
  if (e.status === 500 && e.message.includes("upload failed")) {
    await backoff(3, () => uploadToOrgAssets(orgId, file)); // safe to retry idempotent uploads
  }
}

Prevention

When it happens

Trigger: UploadAsset returns an error from the storage backend or the event/command layer: bucket missing, credentials invalid, network failure to S3/GCS, or command-side validation (e.g. asset type not allowed for the resource owner).

Common situations: Misconfigured S3 endpoint/keys in the storage config; MinIO not reachable; permission denied writing to the bucket; database connectivity issues during the command commit.

Related errors


AI-assisted analysis of zitadel/zitadel@13948f2bcd (2026-09-06). Data as JSON: /api/errors/25f58e075bc7d82e. Report an issue: GitHub.