{"record":{"id":"24fecb581d472170","repo":"juicedata/juicefs","slug":"invalid-gc-meta-record-size-d","errorCode":null,"errorMessage":"invalid gc meta record size: %d","messagePattern":"invalid gc meta record size: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/gc_external.go","lineNumber":220,"sourceCode":"\t\treturn gcObjectRecord{}, false\n\t}\n\treturn gcObjectRecord{sliceID: sliceID, index: index, blockSize: blockSize, objectSize: obj.Size(), key: obj.Key()}, true\n}\n\ntype gcMetaRecord struct {\n\tsliceID uint64\n\tsize    uint32\n\tstate   uint8\n}\n\nconst (\n\tgcMetaRecordSize        = 13\n\tgcObjectRecordFixedSize = 24\n)\n\nfunc gcMetaRecordFromBytes(data []byte) (gcMetaRecord, error) {\n\tif len(data) != gcMetaRecordSize {\n\t\treturn gcMetaRecord{}, errors.Errorf(\"invalid gc meta record size: %d\", len(data))\n\t}\n\trb := utils.FromBuffer(data)\n\treturn gcMetaRecord{\n\t\tsliceID: rb.Get64(),\n\t\tsize:    rb.Get32(),\n\t\tstate:   rb.Get8(),\n\t}, nil\n}\n\nfunc gcMetaRecordToBytes(r gcMetaRecord) ([]byte, error) {\n\twb := utils.NewBuffer(gcMetaRecordSize)\n\twb.Put64(r.sliceID)\n\twb.Put32(r.size)\n\twb.Put8(r.state)\n\treturn wb.Bytes(), nil\n}\n\nfunc compareGcMetaRecord(a, b gcMetaRecord) int {","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/cmd/gc_external.go#L202-L238","documentation":"Returned by gcMetaRecordFromBytes when a serialized gc meta record read back from the external sort spill files is not exactly 13 bytes (8-byte sliceID + 4-byte size + 1-byte state). This indicates corruption of the external sort intermediate data, guarded by the sorter's Checksum option.","triggerScenarios":"Only occurs when extsort deserializes spill segments during gc's external sort and a segment file is truncated or corrupted (partial write, disk issue, or a bug in record serialization), so the FromBytes codec receives a byte slice whose length differs from gcMetaRecordSize (13).","commonSituations":"Disk full causing truncated spill files; corrupted temp files in --sort-dir after a crash; I/O errors on the sort volume; tampered or manually cleaned work directory mid-run.","solutions":["Delete stale contents of the sort work directory and re-run `juicefs gc` with --sort-dir pointing to a clean directory","Check the sort-dir filesystem for errors (dmesg, fsck) and free disk space","Run gc without external sort (smaller dataset) to bypass the extsort path","If reproducible, file a bug with the JuiceFS version — record sizes are fixed constants and should never mismatch"],"exampleFix":"// before\n# corrupted leftovers in sort dir cause the error\njuicefs gc --sort-dir /tmp/gc-sort sqlite3://test.db\n// after\nrm -rf /tmp/gc-sort/* && juicefs gc --sort-dir /tmp/gc-sort sqlite3://test.db","handlingStrategy":"fallback","validationCode":"if fi, err := os.Stat(sortDir); err == nil && fi.IsDir() { /* start from a clean dir */ os.RemoveAll(filepath.Join(sortDir, \"gc-meta-*\")) }","typeGuard":null,"tryCatchPattern":"if err := gcExternalSort(...); err != nil {\n\tif strings.Contains(err.Error(), \"invalid gc meta record size\") {\n\t\tos.RemoveAll(sortDir); /* clean and retry once */\n\t}\n}","preventionTips":["Never reuse a sort directory after a crashed/killed gc run","Keep the sort volume from filling up (monitor df)","Run gc to completion or clean up spill files after abort"],"tags":["gc","external-sort","corruption","deserialization"],"backgroundTag":"checksum-mismatch","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}