dutchcoders/transfer.sh · error
Could not save metadata
Error message
Could not save metadata
What it means
After successfully encoding the metadata JSON, postHandler calls s.storage.Put to persist it as `<filename>.metadata` alongside the file. If the storage backend (local filesystem, S3, GCS, etc.) returns an error, the server responds with 500 and this message. The file itself has not yet been uploaded, so the upload of that part failed entirely.
Source
Thrown at server/handlers.go:527
if status != clamavScanStatusOK {
s.logger.Printf("prescan positive: %s", status)
http.Error(w, "Clamav prescan found a virus", http.StatusPreconditionFailed)
return
}
}
metadata := metadataForRequest(contentType, contentLength, s.randomTokenLength, r)
buffer := &bytes.Buffer{}
if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
s.logger.Printf("%s", err.Error())
http.Error(w, "Could not encode metadata", http.StatusInternalServerError)
return
} else if err := s.storage.Put(r.Context(), token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
s.logger.Printf("%s", err.Error())
http.Error(w, "Could not save metadata", http.StatusInternalServerError)
return
}
s.logger.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
reader, err := attachEncryptionReader(file, r.Header.Get("X-Encrypt-Password"))
if err != nil {
http.Error(w, "Could not crypt file", http.StatusInternalServerError)
return
}
if err = s.storage.Put(r.Context(), token, filename, reader, contentType, uint64(contentLength)); err != nil {
s.logger.Printf("Backend storage error: %s", err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}View on GitHub (pinned to c37bfd9579)
Solutions
- Read the server log line emitted immediately before this response — it contains the underlying storage error.
- Verify storage backend configuration and credentials (bucket name, keys, service account).
- Check local storage path permissions and free disk space if using the local backend.
- Retry the upload; for transient cloud errors this typically succeeds later.
- As an operator, add health checks/monitoring for the storage backend.
Example fix
// before: retrying blindly without checking storage health
resp, _ := http.Post(url, mime, body)
// after: check backend reachability first
if err := checkStorageHealth(); err != nil {
return fmt.Errorf("storage unavailable, postpone upload: %w", err)
}
resp, _ = http.Post(url, mime, body) Defensive patterns
Strategy: retry
Validate before calling
// Health-check the storage backend before uploading
func storageHealthy() error {
resp, err := http.Get(storageHealthURL)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 500 {
return fmt.Errorf("storage unhealthy: %s", resp.Status)
}
return nil
} Try / catch
for attempt := 0; attempt < 3; attempt++ {
resp, err := http.Post(url, mime, body)
if err == nil && resp.StatusCode < 500 {
break // not a transient storage failure
}
time.Sleep(backoff(attempt))
} Prevention
- Verify storage credentials and bucket names in deployment config before rollout.
- Monitor disk space on local-storage deployments.
- Use exponential backoff for transient cloud storage errors.
- Alert on storage backend health endpoints.
When it happens
Trigger: Any storage.Put failure on the metadata object: backend outage, misconfigured bucket/container, expired or missing credentials, disk full on local storage, permission denied on the storage path, network timeout to the object store.
Common situations: S3 credentials revoked or bucket deleted; local temp/storage directory not writable by the server user; transient network errors to cloud storage; storage backend quota exceeded.
Related errors
- could not save metadata
- Clamav prescan found a virus
- Could not encode metadata
- Could not crypt file
- metadata doesn't exist
AI-assisted analysis of dutchcoders/transfer.sh@c37bfd9579 (2026-09-05).
Data as JSON: /api/errors/31c66e53aaa05226.
Report an issue: GitHub.