{"record":{"id":"df56b21576c856f7","repo":"lionsoul2014/ip2region","slug":"handle-read-w","errorCode":null,"errorMessage":"handle read: %w","messagePattern":"handle read: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"binding/golang/xdb/searcher.go","lineNumber":222,"sourceCode":"// do the data read operation based on the setting.\n// content buffer first or will read from the file.\n// this operation will invoke the Seek for file based read.\nfunc (s *Searcher) read(offset int64, buff []byte) error {\n\tif s.contentBuff != nil {\n\t\tcLen := copy(buff, s.contentBuff[offset:])\n\t\tif cLen != len(buff) {\n\t\t\treturn fmt.Errorf(\"incomplete read: readed bytes should be %d\", len(buff))\n\t\t}\n\t} else {\n\t\t_, err := s.dbReader.Seek(offset, 0)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"seek to %d: %w\", offset, err)\n\t\t}\n\n\t\ts.ioCount++\n\t\trLen, err := s.dbReader.Read(buff)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"handle read: %w\", err)\n\t\t}\n\n\t\tif rLen != len(buff) {\n\t\t\treturn fmt.Errorf(\"incomplete read: readed bytes should be %d\", len(buff))\n\t\t}\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":204,"sourceCodeEnd":232,"githubUrl":"https://github.com/lionsoul2014/ip2region/blob/c1a1fc7d5941760db3f8431dc05c48cf7f0e30a1/binding/golang/xdb/searcher.go#L204-L232","documentation":"Go xdb searcher file-mode read: the Read after a successful Seek failed (or the handle was invalidated); the wrapped error carries the OS-level read failure — usually the xdb file was removed, replaced, or the disk errored mid-search.","triggerScenarios":"Disk/network I/O error mid-read; reading at an offset at/after EOF because the xdb is truncated or the offset is corrupted; reading from a special/pipe-backed file that errors on read.","commonSituations":"Truncated xdb on disk; flaky NFS/S3-mounted file; file replaced by a shorter version while a searcher holds the old descriptor.","solutions":["Verify the xdb file size matches header.Length and re-download if truncated.","Reopen the searcher after the file changes.","Retry once on transient I/O errors; xdb reads are stateless (each read seeks first).","Inspect the wrapped cause for io.EOF vs fs-level errors."],"exampleFix":"// before\nregion, err := searcher.Search(ctx, ip)\n// after\nregion, err := searcher.Search(ctx, ip)\nif err != nil {\n    if errors.Is(err, io.EOF) || errors.Is(err, syscall.EIO) {\n        searcher, err = reloadSearcher() // reopen + retry\n    }\n}","handlingStrategy":"retry","validationCode":"fi, _ := os.Stat(xdbPath)\nhdr, _ := xdb.LoadHeaderFromFile(xdbPath)\nif fi.Size() < int64(hdr.Length) {\n    return fmt.Errorf(\"xdb truncated on disk\")\n}","typeGuard":null,"tryCatchPattern":"var region string\nvar err error\nfor i := 0; i < 2; i++ {\n    region, err = searcher.Search(ctx, ip)\n    if err == nil { break }\n    if !strings.Contains(err.Error(), \"handle read\") { break }\n    searcher, _ = reopenSearcher() // transient I/O: reopen once and retry\n}","preventionTips":["Verify xdb completeness at deploy time (size vs header.Length).","Keep xdb on local disk, not network mounts, for hot paths.","Replace the file atomically and reload the searcher on update.","Retry once on transient read errors — xdb reads are idempotent seeks."],"tags":["golang","io-error","file-read","eof"],"backgroundTag":"incomplete-read","analyzedSha":"c1a1fc7d5941760db3f8431dc05c48cf7f0e30a1","analyzedAt":"2026-09-02T16:58:39.988Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T21:17:11.164Z"}