{"record":{"id":"1b57bba446a97bfb","repo":"getsops/sops","slug":"parts-must-be-at-least-two-bytes","errorCode":null,"errorMessage":"parts must be at least two bytes","messagePattern":"parts must be at least two bytes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shamir/shamir.go","lineNumber":265,"sourceCode":"\t\t}\n\t}\n\n\t// Return the encoded secrets\n\treturn out, nil\n}\n\n// Combine is used to reverse a Split and reconstruct a secret\n// once a `threshold` number of parts are available.\nfunc Combine(parts [][]byte) ([]byte, error) {\n\t// Verify enough parts provided\n\tif len(parts) < 2 {\n\t\treturn nil, fmt.Errorf(\"less than two parts cannot be used to reconstruct the secret\")\n\t}\n\n\t// Verify the parts are all the same length\n\tfirstPartLen := len(parts[0])\n\tif firstPartLen < 2 {\n\t\treturn nil, fmt.Errorf(\"parts must be at least two bytes\")\n\t}\n\tfor i := 1; i < len(parts); i++ {\n\t\tif len(parts[i]) != firstPartLen {\n\t\t\treturn nil, fmt.Errorf(\"all parts must be the same length\")\n\t\t}\n\t}\n\n\t// Create a buffer to store the reconstructed secret\n\tsecret := make([]byte, firstPartLen-1)\n\n\t// Buffer to store the samples\n\txSamples := make([]uint8, len(parts))\n\tySamples := make([]uint8, len(parts))\n\n\t// Set the x value for each sample and ensure no x_sample values are the same,\n\t// otherwise div() can be unhappy\n\t// Check that we don't have any duplicate parts, that is, two or\n\t// more parts with the same x coordinate.","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/shamir/shamir.go#L247-L283","documentation":"Each share is {y1..yN, x}: at minimum one y value plus the x tag byte, so every share must be at least 2 bytes long. Combine() rejects shorter parts because they carry no reconstructable data.","triggerScenarios":"Calling Combine with a part of length 0 or 1 — e.g. truncated file contents, a share string that was trimmed/corrupted, or passing raw secret bytes instead of shares.","commonSituations":"Shares stored in files that were truncated, whitespace-stripped encodings dropping bytes, or users pasting shares into systems that mangled them (e.g. leading zero bytes lost in decimal conversion).","solutions":["Verify each share file/transport preserves the full byte length (base64/hex encode shares for storage/transfer).","Re-collect the corrupted share from a custodian.","Check that raw (non-encoded) share bytes are passed, not transformed values.","Validate len(part) >= 2 and consistent lengths before calling Combine."],"exampleFix":"// before\nshares = append(shares, []byte(trimmedLine)) // possibly mangled text\n// after\nfor _, s := range rawShares {\n    if len(s) < 2 { return fmt.Errorf(\"share too short (%d bytes)\", len(s)) }\n}\nsecret, err := shamir.Combine(shares)","handlingStrategy":"validation","validationCode":"for i, p := range parts {\n    if len(p) < 2 {\n        return fmt.Errorf(\"share %d is %d bytes; must be >= 2 (truncated?)\", i, len(p))\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Base64/hex encode shares before storage or transmission","Never trim or text-process raw share bytes","Verify share file sizes after writing/recording","Re-collect shares that fail length checks"],"tags":["shamir","validation","corrupt-data","go"],"backgroundTag":"shamir-combine-invalid-parts","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}