{"record":{"id":"c5fdcb954e376136","repo":"dgraph-io/badger","slug":"failed-to-read-block-offset-from-index-data-corru","errorCode":null,"errorMessage":"failed to read block offset from index. Data corrupted","messagePattern":"failed to read block offset from index\\. Data corrupted","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"table/table.go","lineNumber":496,"sourceCode":"\t}\n\tif !t.shouldDecrypt() {\n\t\t// If there's no encryption, this points to the mmap'ed buffer.\n\t\tt._index = index\n\t}\n\tt._cheap = &cheapIndex{\n\t\tMaxVersion:        index.MaxVersion(),\n\t\tKeyCount:          index.KeyCount(),\n\t\tUncompressedSize:  index.UncompressedSize(),\n\t\tOnDiskSize:        index.OnDiskSize(),\n\t\tOffsetsLength:     index.OffsetsLength(),\n\t\tBloomFilterLength: index.BloomFilterLength(),\n\t}\n\n\tt.hasBloomFilter = len(index.BloomFilterBytes()) > 0\n\n\tvar bo fb.BlockOffset\n\tif !index.Offsets(&bo, 0) {\n\t\treturn nil, errors.New(\"failed to read block offset from index. Data corrupted\")\n\t}\n\treturn &bo, nil\n}\n\n// KeySplits splits the table into at least n ranges based on the block offsets.\nfunc (t *Table) KeySplits(n int, prefix []byte) []string {\n\tif n == 0 {\n\t\treturn nil\n\t}\n\n\toLen := t.offsetsLength()\n\tjump := oLen / n\n\tif jump == 0 {\n\t\tjump = 1\n\t}\n\n\tvar bo fb.BlockOffset\n\tvar res []string","sourceCodeStart":478,"sourceCodeEnd":514,"githubUrl":"https://github.com/dgraph-io/badger/blob/2a001d466f6b71a917319a1db41f99860e16e269/table/table.go#L478-L514","documentation":"After parsing the index via flatbuffers, initIndex requires at least one block offset. If index.Offsets fails to populate the BlockOffset struct at position 0, the parsed index is structurally invalid and the table is declared corrupted.","triggerScenarios":"initIndex reading an index whose flatbuffer bytes are present but do not decode to a TableIndex with >= 1 Offsets — e.g. the wrong byte range was read due to a corrupted footer, or the index bytes were overwritten.","commonSituations":"Bit rot / bad sectors corrupting index bytes mid-file; decryption of an encrypted table with the wrong key producing garbage; footer values desynced from actual index content.","solutions":["Verify encryption keys are correct and unchanged for encrypted tables","Quarantine the corrupt table file and restore from backup","Run disk health checks (SMART) if multiple tables show this error","Rebuild the database via db.Backup/db.Load"],"exampleFix":"// before: rotating encryption key without rekeying data\n\n// after: key rotation requires re-opening with same key or full re-import\nopt.WithEncryptionKey(sameOriginalKey).WithEncryptionAlgo(aes)\ndb.Backup(w, 0)\n// re-open fresh dir with new key and db.Load(r)","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"db, err := badger.Open(opt)\nif err != nil && strings.Contains(err.Error(), \"failed to read block offset\") {\n    // restore the table from backup or rebuild via Backup/Load\n}","preventionTips":["Keep encryption keys stable; rotate via full re-import, not in place","Schedule disk health monitoring; index bytes sit mid-file where bit rot hits","Maintain regular db.Backup exports for rebuild"],"tags":["data-corruption","flatbuffers","index","encryption"],"backgroundTag":"sst-index-corruption","analyzedSha":"2a001d466f6b71a917319a1db41f99860e16e269","analyzedAt":"2026-09-05T13:00:02.264Z","contentChangedAt":"2026-09-05T13:00:02.264Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}