{"record":{"id":"baa030d5573bc8a7","repo":"OpenNHP/opennhp","slug":"invalid-digit-count-d","errorCode":null,"errorMessage":"invalid digit count: %d","messagePattern":"invalid digit count: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/server/keystore.go","lineNumber":575,"sourceCode":"\t\t WHERE created_at < ?\n\t\t   AND (used = 1 OR expires_at <= ?)`,\n\t\tcutoff, time.Now().Unix(),\n\t)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"keystore: sweep otp: %w\", err)\n\t}\n\tn, err := res.RowsAffected()\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"keystore: sweep otp rows affected: %w\", err)\n\t}\n\treturn n, nil\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────\n\nfunc randomDigits(n int) (string, error) {\n\tif n <= 0 {\n\t\treturn \"\", fmt.Errorf(\"invalid digit count: %d\", n)\n\t}\n\n\tbuf := make([]byte, n)\n\tfor i := range buf {\n\t\tdigit, err := rand.Int(rand.Reader, big.NewInt(10))\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tbuf[i] = byte('0') + byte(digit.Int64())\n\t}\n\treturn string(buf), nil\n}\n","sourceCodeStart":557,"sourceCodeEnd":588,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/server/keystore.go#L557-L588","documentation":"randomDigits(n) validates that the requested OTP length is positive before allocating the digit buffer and consuming crypto/rand. A zero or negative n produces this error immediately; it is a pure input-validation failure, not a randomness failure. The only current caller, GenerateOTP, passes a configured length.","triggerScenarios":"GenerateOTP (or any direct caller of randomDigits) invoked with n <= 0 — typically an OTP length config value of 0, a negative value, or an unset/zero-valued config field.","commonSituations":"config.toml missing the otp length setting so Go's zero value (0) is used; a TOML typo like `otp_length = -6`; programmatic use of the keystore API without setting the length.","solutions":["Set a positive OTP length in the server config (e.g. otp_length = 6) and restart nhp-serverd.","Clamp/validate the configured length in the loader: if n <= 0, default to 6.","If calling randomDigits directly, guard with `if n <= 0 { n = 6 }` before invoking.","Add a startup validation that fails fast with a clear message when the configured OTP length is not in 4..12."],"exampleFix":"// before\nn := cfg.OTPLength // 0 when unset\notp, err := randomDigits(n)\n// after\nn := cfg.OTPLength\nif n <= 0 {\n    n = 6 // sensible default\n}\notp, err := randomDigits(n)","handlingStrategy":"validation","validationCode":"if cfg.OTPLength <= 0 {\n    return errors.New(\"otp_length must be > 0 in server config\")\n}","typeGuard":"func validOTPLength(n int) bool { return n >= 4 && n <= 12 }","tryCatchPattern":"otp, err := GenerateOTP()\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid digit count\") {\n        return fmt.Errorf(\"check otp_length config: %w\", err)\n    }\n    return err\n}","preventionTips":["Always set a positive otp_length in config.toml","Apply a default (e.g. 6) when the config field is absent","Validate numeric config ranges at startup, fail fast","Add a unit test asserting GenerateOTP works with the shipped default config"],"tags":["go","validation","otp","configuration"],"backgroundTag":"invalid-argument-value","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}