{"record":{"id":"6c74a117b611bc3e","repo":"getsops/sops","slug":"less-than-two-parts-cannot-be-used-to-reconstruct","errorCode":null,"errorMessage":"less than two parts cannot be used to reconstruct the secret","messagePattern":"less than two parts cannot be used to reconstruct the secret","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shamir/shamir.go","lineNumber":259,"sourceCode":"\t\t\t// Add 1 to the xCoordinate because if it's 0,\n\t\t\t// then the result of p.evaluate(x) will be our secret\n\t\t\tx := uint8(i) + 1\n\t\t\t// Evaluate the polynomial at x\n\t\t\ty := p.evaluate(x)\n\t\t\tout[i][idx] = y\n\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))","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/shamir/shamir.go#L241-L277","documentation":"Combine() needs at least 2 shares to perform Lagrange interpolation; with 0 or 1 parts reconstruction is impossible. The library validates the minimum count before doing any math.","triggerScenarios":"Calling Combine(parts) with an empty slice or a single share, e.g. Combine([][]byte{}) or Combine([][]byte{share1}).","commonSituations":"Only one custodian responded with their share, shares were lost/never collected, or an empty slice from a failed read of stored shares.","solutions":["Collect and pass at least `threshold` shares (minimum 2).","Check the collection step that assembled the parts slice for empty/failed reads.","Guard the call site with len(parts) >= expectedThreshold."],"exampleFix":"// before\nsecret, err := shamir.Combine([][]byte{share1})\n// after\nif len(shares) < threshold { return fmt.Errorf(\"need %d shares, have %d\", threshold, len(shares)) }\nsecret, err := shamir.Combine(shares)","handlingStrategy":"validation","validationCode":"if len(parts) < threshold {\n    return fmt.Errorf(\"need at least %d shares to combine, got %d\", threshold, len(parts))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Collect all shares before attempting Combine","Track share custody so shares aren't lost","Reject empty share collections at ingestion time"],"tags":["shamir","validation","argument-error","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"}