EpicGames/lore · error · anyhow::Error
presigned_url_hmac_key must be at least
Error message
presigned_url_hmac_key must be at least {MIN_HMAC_KEY_BYTES} bytes, got {} What it means
After successfully hex-decoding presigned_url_hmac_key, build_presign_config checks the decoded byte length against MIN_HMAC_KEY_BYTES and bails if the key is too short. Weak HMAC keys would allow presigned-URL signature forgery, so the server refuses to start.
Solutions
- Generate a longer key: `openssl rand -hex 32` and update the config.
- Check the decoded length: (hex_string.len() / 2) must be >= MIN_HMAC_KEY_BYTES.
- Rotate the short key in the upstream secret store and redeploy with the new value.
Example fix
// before presigned_url_hmac_key = "00112233445566778899aabbccddeeff" // 16 bytes // after presigned_url_hmac_key = "<output of: openssl rand -hex 32>" // 32 bytes
Defensive patterns
Strategy: validation
Validate before calling
const MIN_HMAC_KEY_BYTES: usize = 32;
fn key_is_long_enough(hex_key: &str) -> bool {
hex::decode(hex_key).map(|b| b.len() >= MIN_HMAC_KEY_BYTES).unwrap_or(false)
} Prevention
- Always generate 256-bit (32-byte) HMAC keys; never reuse short test secrets in prod.
- Add a config lint that checks decoded key length before deploy.
- Keep keys in a secret manager and rotate to new full-length values.
When it happens
Trigger: PresignSettings.hmac_key decodes to fewer than MIN_HMAC_KEY_BYTES bytes, e.g. hex string of a 16-byte key passed where 32 bytes are required.
Common situations: Developers use a short test secret like "deadbeef"; a legacy deployment predates the minimum-length requirement; someone truncated the key during copy-paste.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- presigned_url_hmac_key is not valid hex
- {} {err}
- Failed to start maintenance HTTP server
- Failed to start HTTP server
- TLS is partially configured: cert_file and pkey_file must…
AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13).
Data as JSON: /api/errors/0c8a7461cdb2d13f.
Report an issue: GitHub.
Appendix: source
Thrown at lore-server/src/http/server.rs:207
/// Renders the resolved allowlist for the startup log.
fn describe_allowed_types(types: &[String]) -> String {
if types.is_empty() {
"<none>".to_string()
} else {
types.join(", ")
}
}
fn build_presign_config(settings: &PresignSettings) -> Result<Option<PresignConfig>> {
let Some(key_hex) = settings.hmac_key.as_deref() else {
return Ok(None);
};
let key_bytes = hex::decode(key_hex)
.map_err(|e| anyhow::anyhow!("presigned_url_hmac_key is not valid hex: {e}"))?;
if key_bytes.len() < MIN_HMAC_KEY_BYTES {
anyhow::bail!(
"presigned_url_hmac_key must be at least {MIN_HMAC_KEY_BYTES} bytes, got {}",
key_bytes.len()
);
}
let key_id = blake3::hash(&key_bytes).to_hex()[..16].to_string();
let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, &key_bytes);
Ok(Some(PresignConfig {
hmac_key,
key_id,
min_ttl_seconds: settings.min_ttl_seconds,
default_ttl_seconds: settings.default_ttl_seconds,
max_ttl_seconds: settings.max_ttl_seconds,
content_type_allowlist: ContentTypeAllowlist::try_from_policy(
&settings.content_type_policy,
)
.map_err(|err| anyhow!("{} {err}", presign_content_type_field(err.field())))?,View on GitHub (pinned to 074eb0b0d1)