jdx/mise · error
relay log format must be text or jsonl
Error message
relay log format must be text or jsonl
What it means
configure validates the relay log format (from --github-relay-log-format or settings.github_relay.log_format) against the two supported values, 'text' and 'jsonl', using matches!. Anything else — including an empty string or misspelling like 'json' or 'structured' — bails with this error.
Solutions
- Set the format to exactly "jsonl" for newline-delimited JSON logs
- Or set it to "text" for human-readable logs
- Check the github_relay.log_format value in your settings/config file for typos
Example fix
// before (settings) [github_relay] log_format = "json" // after [github_relay] log_format = "jsonl"
Defensive patterns
Strategy: validation
Validate before calling
// Pre-validate the configured format
let format = std::env::var("GITHUB_RELAY_LOG_FORMAT").unwrap_or_default();
assert!(format.is_empty() || matches!(format.as_str(), "text" | "jsonl"), "log format must be text or jsonl"); Try / catch
match err {
RelayConfigError::BadLogFormat => eprintln!("set github_relay.log_format to 'text' or 'jsonl'"),
e => return Err(e),
} Prevention
- Use only documented values: 'text' and 'jsonl'
- Note that ndjson == jsonl here; do not invent names
- Validate config at load time with a lint/test
- Grep config files for log_format when onboarding
When it happens
Trigger: configure called with format=Some("json") (or any value other than "text"/"jsonl"), or settings.github_relay.log_format in mise.toml/config set to an unsupported string.
Common situations: Typo in the config file (e.g. 'json' instead of 'jsonl'); guessing format names from other tools ('pretty', 'ndjson'); copy-pasting a config from a different tool.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- relay request timeout must be greater than zero
- encrypt an external dotfile source instead of configuration
- relay concurrency must be between 1 and 32
- relay duration is too large
- relay options require --github-relay-read-only
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/3b99abd7a3b0ab1f.
Report an issue: GitHub.
Appendix: source
Thrown at src/github_relay.rs:94
/// Resolve observability and limits only after explicit access authorization.
pub(crate) fn configure(
scope: Option<Scope>,
log_requests: bool,
no_log_requests: bool,
format: Option<&str>,
max_duration: Option<&str>,
) -> Result<Option<Scope>> {
let Some(scope) = scope else {
if log_requests || no_log_requests || format.is_some() || max_duration.is_some() {
bail!("relay options require --github-relay-read-only");
}
return Ok(None);
};
let settings = crate::config::Settings::get();
let settings = &settings.github_relay;
let format = format.unwrap_or(&settings.log_format);
if !matches!(format, "text" | "jsonl") {
bail!("relay log format must be text or jsonl");
}
let timeout = duration::parse_duration(&settings.request_timeout)?;
if timeout.is_zero() {
bail!("relay request timeout must be greater than zero");
}
if !(1..=32).contains(&settings.concurrency) {
bail!("relay concurrency must be between 1 and 32");
}
let max_duration = duration::parse_duration(max_duration.unwrap_or(&settings.max_duration))?;
if std::time::Instant::now().checked_add(timeout).is_none()
|| std::time::Instant::now()
.checked_add(max_duration)
.is_none()
{
bail!("relay duration is too large");
}
#[cfg(not(unix))]
let _ = max_duration;View on GitHub (pinned to 533346cc37)