{"record":{"id":"7c4a0f43be9ba003","repo":"dgraph-io/badger","slug":"invalid-index-length-in-footer-data-corrupted","errorCode":null,"errorMessage":"invalid index length in footer. Data corrupted","messagePattern":"invalid index length in footer\\. Data corrupted","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"table/table.go","lineNumber":463,"sourceCode":"\t// Read checksum.\n\texpectedChk := &pb.Checksum{}\n\treadPos -= checksumLen\n\tbuf = t.readNoFail(readPos, checksumLen)\n\tif err := proto.Unmarshal(buf, expectedChk); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Read index size from the footer.\n\tif readPos < 4 {\n\t\treturn nil, errors.New(\"invalid table size in footer. Data corrupted\")\n\t}\n\treadPos -= 4\n\tbuf = t.readNoFail(readPos, 4)\n\tt.indexLen = int(y.BytesToU32(buf))\n\t// A table always has at least one block, so a zero indexLen is always\n\t// corruption, and the index must fit in the bytes remaining before readPos.\n\tif t.indexLen <= 0 || t.indexLen > readPos {\n\t\treturn nil, errors.New(\"invalid index length in footer. Data corrupted\")\n\t}\n\n\t// Read index.\n\treadPos -= t.indexLen\n\tt.indexStart = readPos\n\tdata := t.readNoFail(readPos, t.indexLen)\n\n\tif err := y.VerifyChecksum(data, expectedChk); err != nil {\n\t\treturn nil, y.Wrapf(err, \"failed to verify checksum for table: %s\", t.Filename())\n\t}\n\n\tindex, err := t.readTableIndex()\n\tif err != nil {\n\t\treturn nil, err\n\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","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/dgraph-io/badger/blob/2a001d466f6b71a917319a1db41f99860e16e269/table/table.go#L445-L481","documentation":"The index length read from the footer must be positive and must fit within the bytes remaining between the footer and the start of the file. Zero is always invalid (every table has at least one block, hence a non-empty index); too-large values indicate corruption.","triggerScenarios":"Opening a table whose footer's indexLen field is zero, negative (uint32 overflow), or exceeds the remaining readable bytes — corrupted footer, garbage tail bytes, or cross-version format mismatch.","commonSituations":"Tail-overwritten SSTs after disk issues; files copied from an incompatible format; interrupted writes producing zero-filled footer regions.","solutions":["Quarantine the offending SST file and let Badger continue with remaining tables","Restore the file from a verified backup and compare checksums","Confirm all files were produced by the same Badger major version","If corruption is widespread, restore the whole directory or rebuild via db.Load"],"exampleFix":"// before: retrying db.Open on the same corrupt dir\n\n// after: move corrupt table aside, reopen\ntableSize, _ := t.Size()\n_ = tableSize\nos.Rename(\"data/000012.sst\", \"data/000012.sst.corrupt\")\ndb, err := badger.Open(opt)","handlingStrategy":"fallback","validationCode":"// inspect footer indexLen yourself before trusting the dir\nidxLen := binary.LittleEndian.Uint32(tail[8:12])\nif idxLen == 0 || int(idxLen) > len(data)-12 {\n    os.Rename(tablePath, tablePath+\".corrupt\") // let DB open without it\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Quarantine individual corrupt tables instead of blocking DB open","Keep verified backups of the data directory","Confirm uniform Badger versions across all writers (shared NFS etc.)"],"tags":["data-corruption","footer","index","storage"],"backgroundTag":"sst-footer-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"}