{"record":{"id":"31c66e53aaa05226","repo":"dutchcoders/transfer.sh","slug":"could-not-save-metadata-31c66e","errorCode":null,"errorMessage":"Could not save metadata","messagePattern":"Could not save metadata","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"server/handlers.go","lineNumber":527,"sourceCode":"\n\t\t\t\tif status != clamavScanStatusOK {\n\t\t\t\t\ts.logger.Printf(\"prescan positive: %s\", status)\n\t\t\t\t\thttp.Error(w, \"Clamav prescan found a virus\", http.StatusPreconditionFailed)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmetadata := metadataForRequest(contentType, contentLength, s.randomTokenLength, r)\n\n\t\t\tbuffer := &bytes.Buffer{}\n\t\t\tif err := json.NewEncoder(buffer).Encode(metadata); err != nil {\n\t\t\t\ts.logger.Printf(\"%s\", err.Error())\n\t\t\t\thttp.Error(w, \"Could not encode metadata\", http.StatusInternalServerError)\n\n\t\t\t\treturn\n\t\t\t} else if err := s.storage.Put(r.Context(), token, fmt.Sprintf(\"%s.metadata\", filename), buffer, \"text/json\", uint64(buffer.Len())); err != nil {\n\t\t\t\ts.logger.Printf(\"%s\", err.Error())\n\t\t\t\thttp.Error(w, \"Could not save metadata\", http.StatusInternalServerError)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ts.logger.Printf(\"Uploading %s %s %d %s\", token, filename, contentLength, contentType)\n\n\t\t\treader, err := attachEncryptionReader(file, r.Header.Get(\"X-Encrypt-Password\"))\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(w, \"Could not crypt file\", http.StatusInternalServerError)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif err = s.storage.Put(r.Context(), token, filename, reader, contentType, uint64(contentLength)); err != nil {\n\t\t\t\ts.logger.Printf(\"Backend storage error: %s\", err.Error())\n\t\t\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\t\t\treturn\n\n\t\t\t}","sourceCodeStart":509,"sourceCodeEnd":545,"githubUrl":"https://github.com/dutchcoders/transfer.sh/blob/c37bfd95797fd6da8a6da53fc13d191994b3f687/server/handlers.go#L509-L545","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: retrying blindly without checking storage health\nresp, _ := http.Post(url, mime, body)\n// after: check backend reachability first\nif err := checkStorageHealth(); err != nil {\n    return fmt.Errorf(\"storage unavailable, postpone upload: %w\", err)\n}\nresp, _ = http.Post(url, mime, body)","handlingStrategy":"retry","validationCode":"// Health-check the storage backend before uploading\nfunc storageHealthy() error {\n    resp, err := http.Get(storageHealthURL)\n    if err != nil {\n        return err\n    }\n    defer resp.Body.Close()\n    if resp.StatusCode >= 500 {\n        return fmt.Errorf(\"storage unhealthy: %s\", resp.Status)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"for attempt := 0; attempt < 3; attempt++ {\n    resp, err := http.Post(url, mime, body)\n    if err == nil && resp.StatusCode < 500 {\n        break // not a transient storage failure\n    }\n    time.Sleep(backoff(attempt))\n}","preventionTips":["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."],"tags":["storage","http","server","backend","persistence"],"backgroundTag":"storage-write-failed","analyzedSha":"c37bfd95797fd6da8a6da53fc13d191994b3f687","analyzedAt":"2026-09-05T10:21:07.548Z","contentChangedAt":"2026-09-05T10:21:07.548Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}