{"record":{"id":"060d63cc1b957ebc","repo":"lionsoul2014/ip2region","slug":"read-vector-index-block-at-d-w","errorCode":null,"errorMessage":"read vector index block at %d: %w","messagePattern":"read vector index block at (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"binding/golang/xdb/searcher.go","lineNumber":149,"sourceCode":"\t// reset the global ioCount\n\ts.ioCount = 0\n\n\t// locate the segment index block based on the vector index\n\tvar il0, il1 = int(ipBytes[0]), int(ipBytes[1])\n\tvar idx = il0*VectorIndexCols*VectorIndexSize + il1*VectorIndexSize\n\tvar sPtr, ePtr = uint32(0), uint32(0)\n\tif s.vectorIndex != nil {\n\t\tsPtr = binary.LittleEndian.Uint32(s.vectorIndex[idx:])\n\t\tePtr = binary.LittleEndian.Uint32(s.vectorIndex[idx+4:])\n\t} else if s.contentBuff != nil {\n\t\tsPtr = binary.LittleEndian.Uint32(s.contentBuff[HeaderInfoLength+idx:])\n\t\tePtr = binary.LittleEndian.Uint32(s.contentBuff[HeaderInfoLength+idx+4:])\n\t} else {\n\t\t// read the vector index block\n\t\tvar buff = make([]byte, VectorIndexSize)\n\t\terr := s.read(int64(HeaderInfoLength+idx), buff)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"read vector index block at %d: %w\", HeaderInfoLength+idx, err)\n\t\t}\n\n\t\tsPtr = binary.LittleEndian.Uint32(buff)\n\t\tePtr = binary.LittleEndian.Uint32(buff[4:])\n\t}\n\n\t// fmt.Printf(\"sPtr=%d, ePtr=%d\\n\", sPtr, ePtr)\n\t// @Note: ptr validate, zero ptr means source data missing\n\t// so we could just stop here and return an empty string.\n\tif sPtr == 0 || ePtr == 0 {\n\t\treturn \"\", nil\n\t}\n\n\t// binary search the segment index to get the region\n\tvar bytes, dBytes = len(ipBytes), len(ipBytes) << 1\n\tvar segIndexSize = uint32(s.version.SegmentIndexSize)\n\tvar dataLen, dataPtr = 0, uint32(0)\n\tvar buff = make([]byte, segIndexSize)","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/lionsoul2014/ip2region/blob/c1a1fc7d5941760db3f8431dc05c48cf7f0e30a1/binding/golang/xdb/searcher.go#L131-L167","documentation":"While locating the IP, Search reads the 8-byte vector index block for the target's 5-bit prefix. If the underlying read (file seek+read or content-buffer copy) fails, the error is wrapped with the absolute block offset for diagnosis.","triggerScenarios":"File-based searcher: xdb file unreadable, deleted, or I/O error at offset HeaderInfoLength+idx; content-buffer searcher: contentBuff shorter than the vector region because the wrong buffer was supplied to LoadContentFromBuff/NewSearcherWithContent.","commonSituations":"xdb file replaced or truncated while a long-lived searcher holds it open; passing a header-only buffer instead of the whole file content to the content-buffer searcher; disk/permission errors.","solutions":["Check the xdb file size and integrity; the vector area near the file start must be intact.","If using a content buffer, ensure it is the COMPLETE xdb file bytes, not a prefix.","Reload the searcher after the file changes; don't keep stale file handles.","Inspect the wrapped cause (%w) for the OS-level error (permission denied, EOF, etc.)."],"exampleFix":"// before\ncFile, _ := os.ReadFile(path)\nsearcher, _ := xdb.NewSearcherWithContent(header, cFile[:1000])\n// after\ncFile, err := os.ReadFile(path)\nif err != nil { return err }\nsearcher, err := xdb.NewSearcherWithContent(header, cFile) // full content","handlingStrategy":"try-catch","validationCode":"st, err := os.Stat(xdbPath)\nif err != nil { return err }\nif st.Size() < int64(xdb.VectorIndexSize*8+xdb.HeaderInfoLength) {\n    return fmt.Errorf(\"xdb too small for vector index\")\n}","typeGuard":"func hasFullVectorArea(content []byte) bool {\n    return len(content) >= xdb.HeaderInfoLength+8*xdb.VectorIndexSize\n}","tryCatchPattern":"region, err := searcher.Search(ctx, ip)\nif err != nil {\n    if strings.Contains(err.Error(), \"read vector index block\") {\n        searcher, err = reloadSearcher() // full re-read of the xdb\n    }\n    return err\n}","preventionTips":["Use the content-buffer searcher to eliminate per-search file I/O.","Never mutate or slice the content buffer after creating the searcher.","Reload the searcher when the xdb file changes on disk.","Log the offset in the wrapped error to spot corruption patterns."],"tags":["golang","xdb","io-error","vector-index"],"backgroundTag":"xdb-read-failed","analyzedSha":"c1a1fc7d5941760db3f8431dc05c48cf7f0e30a1","analyzedAt":"2026-09-02T16:58:39.988Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T21:17:11.164Z"}