Finding
The akroasis CLI loads a configuration file and environment overrides, then
discards the result. The configuration surface has exactly two possible effects
on the program: abort it before any command runs, or nothing. It can never
configure anything.
run() binds the loaded config to _config and drops it:
fn run() -> Result<(), Error> {
let _config = load_config()?; // loaded, then discarded
let cli = Cli::parse();
...
}
Config carries one field, config_path, which no code reads — load_config
always reads default_config_path() regardless of what config_path says. The
struct is #[serde(deny_unknown_fields)], so every other key is a hard error.
Evidence
crates/akroasis/src/main.rs:133 — let _config = load_config()?;
crates/akroasis/src/main.rs:59-68 — Config with deny_unknown_fields, one
never-read field, behind #[expect(dead_code, reason = "config fields reserved for future CLI options, tracked in #264")]
crates/akroasis/src/main.rs:72-82 — load_config joins
Toml::file(default_config_path()) and Env::prefixed("AKROASIS_")
Behaviour of the built binary (target/debug/akroasis mesh status, run under an
isolated HOME):
| Input |
Exit |
Result |
| no config file, no env |
0 |
works |
AKROASIS_LOG_LEVEL=debug |
1 |
configuration error: unknown field: found \log_level`, expected ``config_path`` for key "LOG_LEVEL" in `AKROASIS_` environment variable(s)` |
config.toml containing log_level = "debug" |
1 |
configuration error: unknown field: found \log_level`, expected ``config_path`` ... TOML file` |
AKROASIS_CONFIG_PATH=/nonexistent/nowhere.toml |
0 |
silently ignored — no error for the missing file, default path still used |
Why this matters
Two distinct failures, and the second is the one that will reach a user first.
Any AKROASIS_* variable in the environment aborts the CLI. Not the command
being run — the whole binary, before dispatch. A user who exports
AKROASIS_LOG_LEVEL once in a shell profile gets every subsequent invocation
failing with a configuration error, including commands that read no
configuration at all. The same applies to any key placed in the config file the
program itself documents as its config file.
The one accepted key is inert. config_path names the behaviour a reader
would expect — relocate the configuration file — and does not do it. A user who
sets it sees no error and no effect, which is worse than rejection: the program
confirms the setting is valid and ignores it.
Together these invert the intent. The strict schema exists to catch typos, but
the schema it enforces contains only a key that does nothing, so strictness
rejects every correct thing a user might write while accepting the one thing
that has no effect.
This sat behind a dead-code suppression reading "config fields reserved for
future CLI options" — the framing was accurate about the field being unused and
silent about the surface being actively harmful. That is the pattern issue 264
exists to surface.
Desired correction
Pick one and make the surface honest about it:
- Wire it. Read
config_path before choosing the file to load (a two-pass
load: resolve the path from CLI/env, then load that file), and add the config
keys the program actually has. Keeps deny_unknown_fields meaningful.
- Remove it. Delete
Config, load_config, and the Config error variant
until there is a setting worth reading. default_config_path and the figment
dependency go with them.
Recommend 2 for now. There is no second config key to justify the surface,
and option 1 spends design effort on a file nothing reads. Removal makes the
absence of configuration true rather than pretended, and the surface can return
when a real setting exists to put in it.
Either way, AKROASIS_* must stop aborting unrelated commands.
Done when:
- No
AKROASIS_* environment variable, and no content in the default config
file, can fail a command that does not read configuration.
- Either
config_path demonstrably relocates the loaded file, or it no longer
exists.
- The
#[expect(dead_code)] on Config is gone rather than re-worded, because
the struct is either read or absent.
Finding
The
akroasisCLI loads a configuration file and environment overrides, thendiscards the result. The configuration surface has exactly two possible effects
on the program: abort it before any command runs, or nothing. It can never
configure anything.
run()binds the loaded config to_configand drops it:Configcarries one field,config_path, which no code reads —load_configalways reads
default_config_path()regardless of whatconfig_pathsays. Thestruct is
#[serde(deny_unknown_fields)], so every other key is a hard error.Evidence
crates/akroasis/src/main.rs:133—let _config = load_config()?;crates/akroasis/src/main.rs:59-68—Configwithdeny_unknown_fields, onenever-read field, behind
#[expect(dead_code, reason = "config fields reserved for future CLI options, tracked in #264")]crates/akroasis/src/main.rs:72-82—load_configjoinsToml::file(default_config_path())andEnv::prefixed("AKROASIS_")Behaviour of the built binary (
target/debug/akroasis mesh status, run under anisolated
HOME):AKROASIS_LOG_LEVEL=debugconfiguration error: unknown field: found \log_level`, expected ``config_path`` for key "LOG_LEVEL" in `AKROASIS_` environment variable(s)`config.tomlcontaininglog_level = "debug"configuration error: unknown field: found \log_level`, expected ``config_path`` ... TOML file`AKROASIS_CONFIG_PATH=/nonexistent/nowhere.tomlWhy this matters
Two distinct failures, and the second is the one that will reach a user first.
Any
AKROASIS_*variable in the environment aborts the CLI. Not the commandbeing run — the whole binary, before dispatch. A user who exports
AKROASIS_LOG_LEVELonce in a shell profile gets every subsequent invocationfailing with a configuration error, including commands that read no
configuration at all. The same applies to any key placed in the config file the
program itself documents as its config file.
The one accepted key is inert.
config_pathnames the behaviour a readerwould expect — relocate the configuration file — and does not do it. A user who
sets it sees no error and no effect, which is worse than rejection: the program
confirms the setting is valid and ignores it.
Together these invert the intent. The strict schema exists to catch typos, but
the schema it enforces contains only a key that does nothing, so strictness
rejects every correct thing a user might write while accepting the one thing
that has no effect.
This sat behind a dead-code suppression reading "config fields reserved for
future CLI options" — the framing was accurate about the field being unused and
silent about the surface being actively harmful. That is the pattern issue 264
exists to surface.
Desired correction
Pick one and make the surface honest about it:
config_pathbefore choosing the file to load (a two-passload: resolve the path from CLI/env, then load that file), and add the config
keys the program actually has. Keeps
deny_unknown_fieldsmeaningful.Config,load_config, and theConfigerror variantuntil there is a setting worth reading.
default_config_pathand the figmentdependency go with them.
Recommend 2 for now. There is no second config key to justify the surface,
and option 1 spends design effort on a file nothing reads. Removal makes the
absence of configuration true rather than pretended, and the surface can return
when a real setting exists to put in it.
Either way,
AKROASIS_*must stop aborting unrelated commands.Done when:
AKROASIS_*environment variable, and no content in the default configfile, can fail a command that does not read configuration.
config_pathdemonstrably relocates the loaded file, or it no longerexists.
#[expect(dead_code)]onConfigis gone rather than re-worded, becausethe struct is either read or absent.