{"record":{"id":"9f93892710dfc57b","repo":"vxcontrol/pentagi","slug":"failed-to-write-temp-file-w","errorCode":null,"errorMessage":"failed to write temp file: %w","messagePattern":"failed to write temp file: %w","errorType":"exception","errorClass":null,"httpStatus":500,"severity":"error","filePath":"backend/pkg/resources/resources.go","lineNumber":290,"sourceCode":"// the temp file. The caller is responsible for removing the temp file on error.\nfunc SaveToTemp(r io.Reader, dir string) (tmpPath string, hash string, size int64, err error) {\n\tif err := os.MkdirAll(dir, 0755); err != nil {\n\t\treturn \"\", \"\", 0, fmt.Errorf(\"failed to create temp directory: %w\", err)\n\t}\n\n\ttmp, err := os.CreateTemp(dir, \".resource-upload-*\")\n\tif err != nil {\n\t\treturn \"\", \"\", 0, fmt.Errorf(\"failed to create temp file: %w\", err)\n\t}\n\ttmpPath = tmp.Name()\n\tdefer tmp.Close()\n\n\th := md5.New()\n\tmw := io.MultiWriter(tmp, h)\n\twritten, copyErr := io.Copy(mw, r)\n\tif copyErr != nil {\n\t\tos.Remove(tmpPath)\n\t\treturn \"\", \"\", 0, fmt.Errorf(\"failed to write temp file: %w\", copyErr)\n\t}\n\tif err := tmp.Chmod(0644); err != nil {\n\t\tos.Remove(tmpPath)\n\t\treturn \"\", \"\", 0, fmt.Errorf(\"failed to set temp file permissions: %w\", err)\n\t}\n\n\treturn tmpPath, hex.EncodeToString(h.Sum(nil)), written, nil\n}\n\n// CommitBlob atomically moves tmpPath to the .blob destination for hash.  If\n// the blob already exists (race with concurrent upload of identical file) the\n// tmp file is removed and no error is returned.\nfunc CommitBlob(dataDir, hash, tmpPath string) error {\n\tif err := validateBlobHash(hash); err != nil {\n\t\treturn err\n\t}\n\tif err := EnsureResourcesDir(dataDir); err != nil {\n\t\treturn err","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/resources/resources.go#L272-L308","documentation":"SaveToTemp streams the reader into the temp file and an MD5 hasher via io.Copy; this error wraps a copy failure. It indicates the upload data could not be fully read or written — a truncated upload, client disconnect, or disk error. The temp file is removed before returning.","triggerScenarios":"HTTP request body closed mid-upload (client disconnect/timeout); disk full while writing; underlying reader (network stream, multipart part) returning an I/O error. Raised via UploadResources.","commonSituations":"Large file uploads exceeding a reverse-proxy body timeout (nginx proxy_read_timeout); user cancels upload in browser; diskquota exceeded on the container volume; flaky network between proxies.","solutions":["Check disk space (df -h) and quotas on the temp directory volume","Increase proxy/server upload timeouts (e.g. nginx client_body_timeout, proxy_read_timeout) for large files","Retry the upload from the client; the error is transient for network causes","Wrap the reader with logging to distinguish client-disconnect from disk errors before calling SaveToTemp"],"exampleFix":"// before\n# nginx default 60s read timeout kills big uploads\nproxy_read_timeout 60s;\n// after\nproxy_read_timeout 600s;\nclient_max_body_size 2G;","handlingStrategy":"try-catch","validationCode":"func diskHasSpace(dir string, min uint64) error {\n\tvar st syscall.Statfs_t\n\tif err := syscall.Statfs(dir, &st); err != nil {\n\t\treturn err\n\t}\n\tavail := st.Bavail * uint64(st.Bsize)\n\tif avail < min {\n\t\treturn fmt.Errorf(\"only %d bytes free in %s\", avail, dir)\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"tmpPath, hash, size, err := resources.SaveToTemp(body, dir)\nif err != nil {\n\tif strings.Contains(err.Error(), \"failed to write temp file\") {\n\t\tif errors.Is(context.Cause(bodyCtx), context.Canceled) {\n\t\t\treturn nil // client disconnected; nothing to do\n\t\t}\n\t\tlog.Error(\"upload copy failed\", \"err\", err) // check disk/proxy timeouts\n\t\treturn http.StatusInsufficientStorage\n\t}\n\treturn err\n}","preventionTips":["Size reverse-proxy timeouts (client_body_timeout, proxy_read_timeout) for your largest uploads","Monitor free disk space and alert before the volume fills","Detect client disconnects via request context so disconnects aren't mistaken for disk errors","Enforce a max upload size before streaming to disk"],"tags":["io","upload","disk-full","network"],"backgroundTag":"upload-write-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}