{"record":{"id":"6896dd99b01a0fb3","repo":"getsops/sops","slug":"threshold-must-be-at-least-2","errorCode":null,"errorMessage":"threshold must be at least 2","messagePattern":"threshold must be at least 2","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shamir/shamir.go","lineNumber":203,"sourceCode":"\t// Addition in GF(2^8) equals XOR:\n\treturn a ^ b\n}\n\n// Split takes an arbitrarily long secret and generates a `parts`\n// number of shares, `threshold` of which are required to reconstruct\n// the secret. The parts and threshold must be at least 2, and less\n// than 256. The returned shares are each one byte longer than the secret\n// as they attach a tag used to reconstruct the secret.\nfunc Split(secret []byte, parts, threshold int) ([][]byte, error) {\n\t// Sanity check the input\n\tif parts < threshold {\n\t\treturn nil, fmt.Errorf(\"parts cannot be less than threshold\")\n\t}\n\tif parts > 255 {\n\t\treturn nil, fmt.Errorf(\"parts cannot exceed 255\")\n\t}\n\tif threshold < 2 {\n\t\treturn nil, fmt.Errorf(\"threshold must be at least 2\")\n\t}\n\tif threshold > 255 {\n\t\treturn nil, fmt.Errorf(\"threshold cannot exceed 255\")\n\t}\n\tif len(secret) == 0 {\n\t\treturn nil, fmt.Errorf(\"cannot split an empty secret\")\n\t}\n\n\t// Allocate the output array, initialize the final byte\n\t// of the output with the offset. The representation of each\n\t// output is {y1, y2, .., yN, x}.\n\tout := make([][]byte, parts)\n\tfor idx := range out {\n\t\t// Store the x coordinate for each part as its last byte\n\t\t// Add 1 to the xCoordinate because if the x coordinate is 0,\n\t\t// then the result of evaluating the polynomial at that point\n\t\t// will be our secret\n\t\tout[idx] = make([]byte, len(secret)+1)","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/shamir/shamir.go#L185-L221","documentation":"A threshold of 1 would mean a single share reconstructs the secret, which defeats the purpose of Shamir secret sharing; Split() enforces threshold >= 2.","triggerScenarios":"Calling Split(secret, parts, threshold) with threshold < 2, e.g. Split(secret, 5, 1) or threshold 0 from an unset config value.","commonSituations":"Default-zero config values, tests probing boundary conditions, or misunderstanding that threshold is a minimum quorum of at least 2.","solutions":["Pass threshold >= 2.","Fix the configuration/source producing a 0 or 1 threshold.","Validate quorum settings before calling Split."],"exampleFix":"// before\nshares, err := shamir.Split(secret, 5, 1)\n// after\nshares, err := shamir.Split(secret, 5, 3)","handlingStrategy":"validation","validationCode":"if threshold < 2 {\n    return fmt.Errorf(\"threshold must be at least 2, got %d\", threshold)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reject threshold 0/1 in config parsing (common zero-value default)","Use a config default of 3 of 5","Document that threshold is a quorum, minimum 2"],"tags":["shamir","validation","argument-error","go"],"backgroundTag":"shamir-split-invalid-args","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}