EpicGames/lore · error · anyhow::Error
presigned_url_hmac_key is not valid hex
Error message
presigned_url_hmac_key is not valid hex: {e} What it means
At startup, build_presign_config reads settings.presigned_url_hmac_key, which must be a hex-encoded HMAC key for signing S3 presigned URLs. If hex::decode fails on that string, the server aborts with this message. The library validates eagerly so bad signing keys never reach request handling.
Solutions
- Hex-encode the key: generate with `openssl rand -hex 32` and set the result verbatim.
- Strip whitespace/quotes and remove any '0x' prefix from the configured value.
- If the key was stored base64-encoded, convert with `base64 -d | xxd -p -c 64`.
- If presigned URLs are not needed, unset the key entirely (build_presign_config returns Ok(None)).
Example fix
// before (config) presigned_url_hmac_key = "0xdeadbeef" // after presigned_url_hmac_key = "deadbeef" // valid hex, >= 32 bytes
Defensive patterns
Strategy: validation
Validate before calling
fn valid_hex_key(key: &str, min_bytes: usize) -> Result<(), String> {
let k = key.trim().trim_start_matches("0x");
hex::decode(k)
.map_err(|e| format!("not valid hex: {e}"))?
.len()
.ge(&min_bytes)
.then_some(())
.ok_or_else(|| format!("key shorter than {min_bytes} bytes"))
} Prevention
- Generate keys with `openssl rand -hex 32` and store them already hex-encoded.
- Validate all secret env vars in CI or an entrypoint pre-flight script.
- Trim whitespace and strip quotes before persisting the value into config.
When it happens
Trigger: Setting presigned_url_hmac_key in the server settings (config file or env) to a value that is not valid hex: odd number of characters, whitespace, '0x' prefix, non-hex characters (g, z, -), or an empty-but-present string.
Common situations: Operators paste a base64 or raw ASCII secret into the config instead of hex; a shell variable carries a trailing newline or quotes; someone prefixes the key with '0x'; YAML/JSON mangling introduces spaces.
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
- presigned_url_hmac_key must be at least
- {} {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/10a8dc4bf3bef98e.
Report an issue: GitHub.
Appendix: source
Thrown at lore-server/src/http/server.rs:204
}
}
/// 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(View on GitHub (pinned to 074eb0b0d1)