crowdsecurity/crowdsec · error
hex master secret decodes to %d bytes; minimum is %d
Error message
hex master secret decodes to %d bytes; minimum is %d
What it means
ParseConfiguredSecret accepts a hex-encoded master secret, and rejects it when the decoded bytes are shorter than minSecretBytes. Hex strings are parsed by character count, so a long-looking hex string can still decode to too little entropy; this error surfaces that directly.
Source
Thrown at pkg/appsec/challenge/secret.go:46
return nil, fmt.Errorf("generate random master secret: %w", err)
}
return buf, nil
}
// ParseConfiguredSecret accepts a configured master secret as either a hex
// string (preferred — encodes raw bytes unambiguously) or a raw passphrase
// (fallback for human-edited configs). The result is at least minSecretBytes.
func ParseConfiguredSecret(value string) ([]byte, error) {
if value == "" {
return nil, errors.New("empty master secret")
}
// Hex form: even length, hex digits only.
if isHex(value) {
raw, err := hex.DecodeString(value)
if err == nil {
if len(raw) < minSecretBytes {
return nil, fmt.Errorf("hex master secret decodes to %d bytes; minimum is %d", len(raw), minSecretBytes)
}
return raw, nil
}
// Fall through to passphrase handling on hex parse failure — defensive.
}
if len(value) < minSecretBytes {
return nil, fmt.Errorf("passphrase master secret is %d bytes; minimum is %d", len(value), minSecretBytes)
}
return []byte(value), nil
}
func isHex(s string) bool {
if s == "" || len(s)%2 != 0 {
return false
}
for i := range len(s) {View on GitHub (pinned to 909b515798)
Solutions
- Generate a 32-byte secret: `openssl rand -hex 32` (64 hex characters) and paste it as master_secret
- Count the hex characters: length/2 must be >= minSecretBytes
- If it was intended as a passphrase, remove hex-looking characters so it falls into the passphrase path (still must meet the byte minimum)
- Update distributed-deployment configs so every instance gets the corrected full-length secret
Example fix
// before: 40 hex chars -> 20 bytes -> rejected master_secret: "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0" // after: 64 hex chars -> 32 bytes master_secret: "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
Defensive patterns
Strategy: validation
Validate before calling
func validHexSecretLen(s string, min int) bool {
raw, err := hex.DecodeString(s)
return err == nil && len(raw) >= min
}
// use: validHexSecretLen(cfg.MasterSecret, 32) Prevention
- Use `openssl rand -hex 32` to generate secrets
- Validate with challenge.ParseConfiguredSecret at config-load time
- Document that hex length must be 2x the byte minimum
- Add config validation to CI for distributed deployment manifests
When it happens
Trigger: BuildOptions parses a configured master_secret that isHex recognizes and hex.DecodeString decodes, but the decoded byte length is below minSecretBytes — e.g. 40 hex chars = 20 bytes.
Common situations: Operator generated a 16/20/24-byte key instead of 32; used an MD5 or SHA-1 hash output as the secret; copy-pasted a partial hex string; test cases like TestParseConfiguredSecret_HexTooShort.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- keyring master secret is %d bytes; minimum is %d
- passphrase master secret is %d bytes; minimum is %d
- missing lapi client credentials
- no appsec_config provided
- missing TLS key file
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/a5ab879cf1a188e1.
Report an issue: GitHub.