{"record":{"id":"6ba2a3b4e9818ffc","repo":"getsops/sops","slug":"cannot-split-an-empty-secret","errorCode":null,"errorMessage":"cannot split an empty secret","messagePattern":"cannot split an empty secret","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shamir/shamir.go","lineNumber":209,"sourceCode":"// 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)\n\t\tout[idx][len(secret)] = uint8(idx) + 1\n\t}\n\n\t// Construct a random polynomial for each byte of the secret.\n\t// Because we are using a field of size 256, we can only represent\n\t// a single byte as the intercept of the polynomial, so we must","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/shamir/shamir.go#L191-L227","documentation":"Split() cannot derive shares from a zero-length secret; each share is built per secret byte, so an empty secret produces meaningless output. The library rejects it explicitly.","triggerScenarios":"Calling Split with an empty (nil or len 0) secret byte slice, often from an empty key-generation result or an unfilled buffer.","commonSituations":"A crypto/rand or key-service call returned an empty slice upstream, or a variable was declared but never populated before splitting.","solutions":["Ensure the secret is generated/populated before calling Split (check len(secret) > 0).","Fix the upstream key-generation function returning empty bytes.","Add a caller-side length check to fail with clearer context."],"exampleFix":"// before\nvar key []byte\nshares, err := shamir.Split(key, 5, 3)\n// after\nkey := make([]byte, 32)\nif _, err := rand.Read(key); err != nil { return err }\nshares, err := shamir.Split(key, 5, 3)","handlingStrategy":"validation","validationCode":"if len(secret) == 0 {\n    return fmt.Errorf(\"secret is empty; check key generation\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check rand.Read return values and slice lengths before splitting","Never split an uninitialized buffer","Fail fast upstream when key generation yields zero bytes"],"tags":["shamir","validation","empty-input","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"}