{"record":{"id":"903d0d8edbfd2229","repo":"vxcontrol/pentagi","slug":"failed-to-compute-md5-w","errorCode":null,"errorMessage":"failed to compute MD5: %w","messagePattern":"failed to compute MD5: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/resources/resources.go","lineNumber":75,"sourceCode":"\tif !IsValidBlobHash(cleanHash) {\n\t\treturn filepath.Join(ResourcesDir(dataDir), invalidBlobHashFileName)\n\t}\n\treturn filepath.Join(ResourcesDir(dataDir), cleanHash+\".blob\")\n}\n\n// EnsureResourcesDir creates the resources storage directory if it does not exist.\nfunc EnsureResourcesDir(dataDir string) error {\n\tif err := os.MkdirAll(ResourcesDir(dataDir), 0755); err != nil {\n\t\treturn fmt.Errorf(\"failed to create resources directory: %w\", err)\n\t}\n\treturn nil\n}\n\n// ComputeFileMD5 reads r to EOF and returns the lowercase hex MD5 digest.\nfunc ComputeFileMD5(r io.Reader) (string, error) {\n\th := md5.New()\n\tif _, err := io.Copy(h, r); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to compute MD5: %w\", err)\n\t}\n\treturn hex.EncodeToString(h.Sum(nil)), nil\n}\n\n// IsValidBlobHash reports whether hash is a hex-encoded MD5 digest.\nfunc IsValidBlobHash(hash string) bool {\n\tif len(hash) != md5.Size*2 {\n\t\treturn false\n\t}\n\tfor _, r := range hash {\n\t\tif (r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F') {\n\t\t\tcontinue\n\t\t}\n\t\treturn false\n\t}\n\treturn true\n}\n","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/resources/resources.go#L57-L93","documentation":"ComputeFileMD5 (resources.go:75) reads an io.Reader to EOF and returns the lowercase hex MD5 digest. The error 'failed to compute MD5: %w' is returned when io.Copy fails while streaming bytes into the md5 hash. It wraps the underlying read error, so the root cause (disk failure, broken pipe, permission error on a file-backed reader) is available via errors.Unwrap or errors.As/Is.","triggerScenarios":"Calling ComputeFileMD5 with a reader whose underlying source fails during read: an *os.File opened on a removed or unreadable file, a network/HTTP body that drops mid-stream, or a bytes.Reader is fine but a custom reader returning an error.","commonSituations":"Hashing a file that was truncated or deleted between open and read; hashing an upload stream that was interrupted; permission changes on the source file; storage device errors in Docker volume backends.","solutions":["Inspect the wrapped cause with errors.Unwrap(err) or %v of the error to find the real I/O failure","Re-check the source file exists and is readable (os.Stat, permissions) before hashing","For streams, retry the read/hash from the start of the stream; partial hashing is not recoverable","If the reader can legitimately fail mid-copy, wrap it with buffering or read it fully into memory only if size permits"],"exampleFix":"// before\nhash, err := resources.ComputeFileMD5(f) // f may be stale/closed\nif err != nil { return err }\n// after\nif _, err := f.Stat(); err != nil { return fmt.Errorf(\"source unavailable: %w\", err) }\nif _, err := f.Seek(0, io.SeekStart); err != nil { return err }\nhash, err := resources.ComputeFileMD5(f)\nif err != nil { return fmt.Errorf(\"hashing failed: %w\", err) }","handlingStrategy":"try-catch","validationCode":"if f, ok := r.(*os.File); ok {\n    if _, err := f.Stat(); err != nil {\n        return fmt.Errorf(\"source unreadable: %w\", err)\n    }\n}","typeGuard":"var _ = func(r io.Reader) bool { return r != nil }","tryCatchPattern":"hash, err := resources.ComputeFileMD5(r)\nif err != nil {\n    var perr *fs.PathError\n    if errors.As(err, &perr) { /* handle open/read failure on path */ }\n    return fmt.Errorf(\"md5 compute failed: %w\", err)\n}","preventionTips":["Stat the source file (exists, readable, size stable) before hashing","For network streams, buffer or retry the whole stream rather than resuming a partial hash","Never hash a file that is still being written; wait for the writer to finish","Log errors.Unwrap(err) to distinguish source I/O issues from hashing bugs"],"tags":["io","md5","file-read"],"backgroundTag":"io-read-failure","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}