{"record":{"id":"a15cc2efba199162","repo":"juicedata/juicefs","slug":"invalid-gc-object-record-size-d","errorCode":null,"errorMessage":"invalid gc object record size: %d","messagePattern":"invalid gc object record size: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/gc_external.go","lineNumber":255,"sourceCode":"\nfunc compareGcMetaRecord(a, b gcMetaRecord) int {\n\tif c := cmp.Compare(a.sliceID, b.sliceID); c != 0 {\n\t\treturn c\n\t}\n\treturn cmp.Compare(a.state, b.state)\n}\n\ntype gcObjectRecord struct {\n\tsliceID    uint64\n\tindex      int\n\tblockSize  int\n\tobjectSize int64\n\tkey        string\n}\n\nfunc gcObjectRecordFromBytes(data []byte) (gcObjectRecord, error) {\n\tif len(data) < gcObjectRecordFixedSize {\n\t\treturn gcObjectRecord{}, errors.Errorf(\"invalid gc object record size: %d\", len(data))\n\t}\n\trb := utils.FromBuffer(data)\n\treturn gcObjectRecord{\n\t\tsliceID:    rb.Get64(),\n\t\tindex:      int(rb.Get32()),\n\t\tblockSize:  int(rb.Get32()),\n\t\tobjectSize: int64(rb.Get64()),\n\t\tkey:        string(rb.Get(len(data) - gcObjectRecordFixedSize)),\n\t}, nil\n}\n\nfunc gcObjectRecordToBytes(r gcObjectRecord) ([]byte, error) {\n\twb := utils.NewBuffer(uint32(gcObjectRecordFixedSize + len(r.key)))\n\twb.Put64(r.sliceID)\n\twb.Put32(uint32(r.index))\n\twb.Put32(uint32(r.blockSize))\n\twb.Put64(uint64(r.objectSize))\n\twb.Put([]byte(r.key))","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/cmd/gc_external.go#L237-L273","documentation":"Returned by gcObjectRecordFromBytes when a serialized gc object record read from the external sort spill files is shorter than the fixed 24-byte prefix (8-byte sliceID + 4-byte index + 4-byte blockSize + 8-byte objectSize; variable key follows). Like its meta counterpart, this signals corrupted or truncated external sort intermediate data.","triggerScenarios":"extsort deserializes gc-object spill segments during gc and a segment is truncated/corrupted so the codec gets fewer than gcObjectRecordFixedSize (24) bytes — partial spill write, disk-full, or I/O corruption in the sort work directory.","commonSituations":"Sort volume ran out of disk space mid-spill; crash or kill during gc leaving partial segment files reused later; faulty disk; manually deleted/edited files in --sort-dir.","solutions":["Clean the sort work directory and re-run `juicefs gc`","Verify disk space and filesystem health on the --sort-dir volume","Bypass external sort for smaller datasets if possible","If reproducible on a clean directory, report a bug with JuiceFS version and gc command line"],"exampleFix":"// before\n# disk full during previous run left truncated segments\njuicefs gc --sort-dir /tmp/gc-sort redis://localhost:6379/1\n// after\ndf -h /tmp && rm -rf /tmp/gc-sort/* && juicefs gc --sort-dir /tmp/gc-sort redis://localhost:6379/1","handlingStrategy":"fallback","validationCode":"if fi, err := os.Stat(sortDir); err == nil && fi.IsDir() { /* start from a clean dir */ os.RemoveAll(filepath.Join(sortDir, \"gc-object-*\")) }","typeGuard":null,"tryCatchPattern":"if err := gcExternalSort(...); err != nil {\n\tif strings.Contains(err.Error(), \"invalid gc object record size\") {\n\t\tos.RemoveAll(sortDir); /* clean and retry once */\n\t}\n}","preventionTips":["Clean spill files after any aborted gc run","Ensure enough free space for object-record spill files (records are larger with keys)","Avoid killing gc mid-spill; use graceful cancellation"],"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-14T00:17:10.932Z"}