Skip to content

fix(settings): distinguish unset known settings from unknown ones#9818

Merged
jdx merged 3 commits into
mainfrom
claude/competent-williams-05ad05
May 12, 2026
Merged

fix(settings): distinguish unset known settings from unknown ones#9818
jdx merged 3 commits into
mainfrom
claude/competent-williams-05ad05

Conversation

@jdx

@jdx jdx commented May 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • mise settings get <key> walked the serialized current settings to look up a value, but Option<T> fields that are None are skipped by TOML serialization. That made unset-but-known settings indistinguishable from typos — both returned Unknown setting.
  • Now: when the walk fails, check SETTINGS_META for the full key. If known, emit Setting [<key>] is not set; otherwise keep Unknown setting.

Reported in #9817.

Before

$ mise settings get python.compile
mise ERROR Unknown setting: python.compile
$ mise settings get not.a.real.setting
mise ERROR Unknown setting: not.a.real.setting

After

$ mise settings get python.compile
mise ERROR Setting [python.compile] is not set
$ mise settings get not.a.real.setting
mise ERROR Unknown setting: not.a.real.setting

Test plan

  • mise settings get python.compileSetting [python.compile] is not set (exit 1)
  • mise settings get cargo.registry_nameSetting [cargo.registry_name] is not set (exit 1)
  • mise settings get abcdefgUnknown setting: abcdefg (unchanged)
  • mise settings get legacy_version_filetrue (unchanged)
  • mise settings get python (parent key) → inline table (unchanged)
  • E2E cli/test_settings_set extended and passing

🤖 Generated with Claude Code


Note

Low Risk
Low risk: small change to mise settings get error handling plus updated e2e expectations; main impact is different user-facing error text for missing known keys.

Overview
mise settings get now distinguishes between a known setting that is currently unset vs a truly unknown key by consulting SETTINGS_META when a lookup fails.

E2E CLI tests are updated/extended to assert the new Setting [<key>] is not set error for known-but-unset keys (including dotted keys), while keeping Unknown setting for typos.

Reviewed by Cursor Bugbot for commit 5186233. Bugbot is set up for automated code reviews on this repo. Configure here.

`mise settings get <key>` walked the serialized current settings to find
a value, but Option<T> fields that are None are skipped by TOML
serialization. That made unset-but-known settings indistinguishable from
typos — both returned `Unknown setting`.

Check SETTINGS_META when the walk fails: if the key is known but unset,
emit `Setting [<key>] is not set`; otherwise keep `Unknown setting`.

Fixes #9817

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes mise settings get so that known settings whose values are None (and therefore absent from TOML serialization) return a distinct error instead of the generic "Unknown setting" message.

  • src/cli/settings/get.rs: When the TOML walk fails to find a key, is_known_setting now consults SETTINGS_META — checking for an exact key match or any key with that prefix — and emits \"Setting [<key>] is not set\" for valid-but-unset settings, keeping \"Unknown setting\" only for genuinely unrecognised keys.
  • E2E tests (test_settings_set, test_settings_unset): Three new assertions cover a leaf-level typo, a valid unset dotted key, and a second plugin's unset key; the unset test is updated to match the new message.

Confidence Score: 5/5

Safe to merge — only the error message path of mise settings get is touched, and new E2E tests guard the new behaviour.

The change is narrow: it only affects the error-handling branch in the TOML walk (no success path is modified), and is_known_setting is a pure read of a static map. The three new E2E assertions directly cover the fix, including the typo-versus-unset distinction. No data, config, or runtime behaviour is altered for any previously-working call.

No files require special attention.

Important Files Changed

Filename Overview
src/cli/settings/get.rs Adds is_known_setting helper using SETTINGS_META to distinguish unset-but-valid keys from unknown ones; walk logic is correct for full and partial paths
e2e/cli/test_settings_set Extends E2E test with three new assertions: typo in dotted key, known-but-unset dotted key, and a second plugin's unset setting
e2e/cli/test_settings_unset Updates expected error message for python.compile after unset to match new "Setting [] is not set" wording

Reviews (3): Last reviewed commit: "test(settings): update test_settings_uns..." | Re-trigger Greptile

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the mise settings get command to distinguish between valid but unset settings and entirely unknown settings, including new E2E tests for these cases. Feedback from the review highlights that the current check only recognizes leaf settings, causing organizational groups to still be reported as unknown. The reviewer suggested a more robust check to include these groups and recommended standardizing error message formatting by consistently using brackets for setting keys.

Comment thread src/cli/settings/get.rs Outdated
Comment on lines 41 to 44
} else if SETTINGS_META.contains_key(self.setting.as_str()) {
bail!("Setting [{}] is not set", self.setting);
} else {
bail!("Unknown setting: {}", self.setting);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current check only identifies leaf settings as 'known'. Organizational groups (e.g., cargo, python) will still report as Unknown setting if they contain no set values, which is inconsistent with the goal of distinguishing known settings from typos.

Additionally, the error messages use different formatting styles (brackets vs. no brackets, and different phrasing). It is better to use a consistent style for both types of errors. Using brackets for the key is consistent with other error messages in the codebase.

Suggested change
} else if SETTINGS_META.contains_key(self.setting.as_str()) {
bail!("Setting [{}] is not set", self.setting);
} else {
bail!("Unknown setting: {}", self.setting);
} else if SETTINGS_META.keys().any(|k| k == &self.setting || k.starts_with(&format!("{}.", self.setting))) {
bail!("Setting [{}] is not set", self.setting);
} else {
bail!("Unknown setting: [{}]", self.setting);

Comment thread e2e/cli/test_settings_set
@@ -13,6 +13,8 @@ assert_contains "mise settings -T" "all_compile = true"
mise settings unset all_compile
assert "mise settings get all_compile" "false"
assert_fail "mise settings get abcdefg" "mise ERROR Unknown setting: abcdefg"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the error message for unknown settings is updated to include brackets for consistency, this test case should be updated to match the new output.

assert_fail "mise settings get abcdefg" "mise ERROR Unknown setting: [abcdefg]"

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request improves the error reporting for the settings get command by distinguishing between unknown settings and settings that are valid but currently unset. It introduces a check against SETTINGS_META to provide more specific error messages. The review feedback suggests enhancing the test suite with a case for settings that have a valid prefix but an invalid leaf name to ensure the 'Unknown setting' logic handles these scenarios correctly.

Comment thread e2e/cli/test_settings_set
Comment on lines 15 to +17
assert_fail "mise settings get abcdefg" "mise ERROR Unknown setting: abcdefg"
assert_fail "mise settings get python.compile" "mise ERROR Setting [python.compile] is not set"
assert_fail "mise settings get cargo.registry_name" "mise ERROR Setting [cargo.registry_name] is not set"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To fully verify that the logic correctly distinguishes between unset known settings and actual typos (unknown settings), it is recommended to add a test case where a key has a valid prefix but an invalid leaf name (e.g., python.compyle). This ensures that the else block in src/cli/settings/get.rs is correctly reached when the full key is not present in SETTINGS_META.

assert_fail "mise settings get abcdefg" "mise ERROR Unknown setting: abcdefg"
assert_fail "mise settings get python.compyle" "mise ERROR Unknown setting: python.compyle"
assert_fail "mise settings get python.compile" "mise ERROR Setting [python.compile] is not set"
assert_fail "mise settings get cargo.registry_name" "mise ERROR Setting [cargo.registry_name] is not set"

jdx and others added 2 commits May 12, 2026 13:33
Addresses review feedback: `mise settings get cargo` should not say
"Unknown setting" if the cargo namespace happens to have no set
values. Match `SETTINGS_META` keys by exact match or namespace prefix.

Also add a test for a typo-with-valid-prefix (`python.compyle`) to
verify it still falls through to "Unknown setting".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The test asserted the old behavior where unset-but-known settings
returned "Unknown setting". Update it to match the new
"Setting [<key>] is not set" message.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.5.6 x -- echo 27.9 ± 2.0 22.9 33.4 1.00
mise x -- echo 28.9 ± 2.3 23.1 34.9 1.04 ± 0.11

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.5.6 env 27.6 ± 2.2 22.2 34.1 1.00
mise env 28.3 ± 2.3 22.5 36.6 1.02 ± 0.12

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.5.6 hook-env 28.5 ± 2.2 23.2 37.2 1.00
mise hook-env 29.4 ± 2.4 23.7 39.3 1.03 ± 0.11

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.5.6 ls 24.2 ± 1.9 19.7 28.6 1.00
mise ls 25.2 ± 2.1 19.6 31.9 1.04 ± 0.12

xtasks/test/perf

Command mise-2026.5.6 mise Variance
install (cached) 159ms 159ms +0%
ls (cached) 91ms 88ms +3%
bin-paths (cached) 89ms 93ms -4%
task-ls (cached) 641ms 646ms +0%

@jdx jdx merged commit 8bb7b78 into main May 12, 2026
31 of 33 checks passed
@jdx jdx deleted the claude/competent-williams-05ad05 branch May 12, 2026 19:01
mise-en-dev added a commit that referenced this pull request May 13, 2026
### 🐛 Bug Fixes

- **(backend)** use runtime paths for backend bin dirs by @risu729 in
[#9606](#9606)
- **(ci)** preserve vendor/aqua-registry/ in PPA publish workflow by
@jdx in [#9782](#9782)
- **(ci)** set UTF-8 locale in e2e Docker image by @jdx in
[#9820](#9820)
- **(ci)** pass UTF-8 locale through to e2e tests by @jdx in
[#9823](#9823)
- **(conda)** dedup repodata by archive identifier instead of URL by
@jdx in [#9831](#9831)
- **(github)** use default shell for credential command by @risu729 in
[#9664](#9664)
- **(settings)** distinguish unset known settings from unknown ones by
@jdx in [#9818](#9818)
- **(upgrade)** remove completed progress jobs to prevent duplicate
output by @jdx in [#9779](#9779)
- **(vfox)** resolve GitHub token lazily inside Lua plugins by @jdx in
[#9816](#9816)

### 🚜 Refactor

- **(config)** separate core and backend tool options by @risu729 in
[#9753](#9753)
- **(schema)** reuse env directive property schemas by @risu729 in
[#9651](#9651)

### 📚 Documentation

- **(aliases)** fix Aliased Versions example and drop stale asdf callout
by @jdx in [#9830](#9830)

### ⚡ Performance

- **(aqua)** use phf for baked registry lookups by @risu729 in
[#9763](#9763)
- **(task)** cache per-file content hashes for
source_freshness_hash_contents by @jdx in
[#9819](#9819)

### 🧪 Testing

- **(e2e)** pin aube to known-good version in npm package_manager test
by @jdx in [#9794](#9794)

### 📦 Registry

- replace unsupported exe options by @risu729 in
[#9587](#9587)
- update pi by @garysassano in
[#9792](#9792)

### Chore

- **(ci)** use non-large runners for release builds by @jdx in
[#9786](#9786)
- **(ci)** compare registry PRs from fork point by @risu729 in
[#9643](#9643)
- **(ci)** make build-copr.sh the single source of truth for COPR
chroots by @jdx in [#9788](#9788)
- **(ci)** use crates.io trusted publishing in release-plz by @jdx in
[#9793](#9793)
- **(ci)** remove autofix.ci workflow by @jdx in
[#9801](#9801)
- **(ci)** restore -large runner for Linux release builds by @jdx in
[#9815](#9815)
- **(ci)** add zizmor workflow for github actions security analysis by
@jdx in [#9804](#9804)
- **(ci)** assert mise run render produces no diff by @jdx in
[#9803](#9803)
- **(copr)** publish EL9 builds via centos-stream+epel-next-9 chroot by
@jdx in [#9787](#9787)

### Ci

- remove pull_request_target workflow by @jdx in
[#9799](#9799)
- remove caching from publishing workflows by @jdx in
[#9800](#9800)

### Security

- reject shell metacharacters in version strings and CI inputs by @jdx
in [#9814](#9814)

## 📦 Aqua Registry Updates

### New Packages (11)

- [`Code-Hex/Neo-cowsay`](https://github.com/Code-Hex/Neo-cowsay)
-
[`SonarSource/sonarqube-cli`](https://github.com/SonarSource/sonarqube-cli)
- [`earendil-works/pi`](https://github.com/earendil-works/pi)
- [`hylo-lang/hylo-new`](https://github.com/hylo-lang/hylo-new)
- [`jfernandez/bpftop`](https://github.com/jfernandez/bpftop)
- [`modem-dev/hunk`](https://github.com/modem-dev/hunk)
- [`npm/cli`](https://github.com/npm/cli)
- [`racket/racket/minimal`](https://github.com/racket/racket)
- [`slackapi/slack-cli`](https://github.com/slackapi/slack-cli)
- [`vectordotdev/vector`](https://github.com/vectordotdev/vector)
- [`wasilibs/go-yamllint`](https://github.com/wasilibs/go-yamllint)

### Updated Packages (10)

- [`DataDog/pup`](https://github.com/DataDog/pup)
- [`aquasecurity/trivy`](https://github.com/aquasecurity/trivy)
- [`astral-sh/uv`](https://github.com/astral-sh/uv)
- [`caarlos0/svu`](https://github.com/caarlos0/svu)
-
[`cargo-bins/cargo-binstall`](https://github.com/cargo-bins/cargo-binstall)
- [`foundry-rs/foundry`](https://github.com/foundry-rs/foundry)
- [`gastownhall/beads`](https://github.com/gastownhall/beads)
-
[`gruntwork-io/terragrunt`](https://github.com/gruntwork-io/terragrunt)
- [`pnpm/pnpm`](https://github.com/pnpm/pnpm)
- [`santosr2/TerraTidy`](https://github.com/santosr2/TerraTidy)
3PeatVR pushed a commit to 3PeatVR/mise that referenced this pull request May 14, 2026
### 🐛 Bug Fixes

- **(backend)** use runtime paths for backend bin dirs by @risu729 in
[jdx#9606](jdx#9606)
- **(ci)** preserve vendor/aqua-registry/ in PPA publish workflow by
@jdx in [jdx#9782](jdx#9782)
- **(ci)** set UTF-8 locale in e2e Docker image by @jdx in
[jdx#9820](jdx#9820)
- **(ci)** pass UTF-8 locale through to e2e tests by @jdx in
[jdx#9823](jdx#9823)
- **(conda)** dedup repodata by archive identifier instead of URL by
@jdx in [jdx#9831](jdx#9831)
- **(github)** use default shell for credential command by @risu729 in
[jdx#9664](jdx#9664)
- **(settings)** distinguish unset known settings from unknown ones by
@jdx in [jdx#9818](jdx#9818)
- **(upgrade)** remove completed progress jobs to prevent duplicate
output by @jdx in [jdx#9779](jdx#9779)
- **(vfox)** resolve GitHub token lazily inside Lua plugins by @jdx in
[jdx#9816](jdx#9816)

### 🚜 Refactor

- **(config)** separate core and backend tool options by @risu729 in
[jdx#9753](jdx#9753)
- **(schema)** reuse env directive property schemas by @risu729 in
[jdx#9651](jdx#9651)

### 📚 Documentation

- **(aliases)** fix Aliased Versions example and drop stale asdf callout
by @jdx in [jdx#9830](jdx#9830)

### ⚡ Performance

- **(aqua)** use phf for baked registry lookups by @risu729 in
[jdx#9763](jdx#9763)
- **(task)** cache per-file content hashes for
source_freshness_hash_contents by @jdx in
[jdx#9819](jdx#9819)

### 🧪 Testing

- **(e2e)** pin aube to known-good version in npm package_manager test
by @jdx in [jdx#9794](jdx#9794)

### 📦 Registry

- replace unsupported exe options by @risu729 in
[jdx#9587](jdx#9587)
- update pi by @garysassano in
[jdx#9792](jdx#9792)

### Chore

- **(ci)** use non-large runners for release builds by @jdx in
[jdx#9786](jdx#9786)
- **(ci)** compare registry PRs from fork point by @risu729 in
[jdx#9643](jdx#9643)
- **(ci)** make build-copr.sh the single source of truth for COPR
chroots by @jdx in [jdx#9788](jdx#9788)
- **(ci)** use crates.io trusted publishing in release-plz by @jdx in
[jdx#9793](jdx#9793)
- **(ci)** remove autofix.ci workflow by @jdx in
[jdx#9801](jdx#9801)
- **(ci)** restore -large runner for Linux release builds by @jdx in
[jdx#9815](jdx#9815)
- **(ci)** add zizmor workflow for github actions security analysis by
@jdx in [jdx#9804](jdx#9804)
- **(ci)** assert mise run render produces no diff by @jdx in
[jdx#9803](jdx#9803)
- **(copr)** publish EL9 builds via centos-stream+epel-next-9 chroot by
@jdx in [jdx#9787](jdx#9787)

### Ci

- remove pull_request_target workflow by @jdx in
[jdx#9799](jdx#9799)
- remove caching from publishing workflows by @jdx in
[jdx#9800](jdx#9800)

### Security

- reject shell metacharacters in version strings and CI inputs by @jdx
in [jdx#9814](jdx#9814)

## 📦 Aqua Registry Updates

### New Packages (11)

- [`Code-Hex/Neo-cowsay`](https://github.com/Code-Hex/Neo-cowsay)
-
[`SonarSource/sonarqube-cli`](https://github.com/SonarSource/sonarqube-cli)
- [`earendil-works/pi`](https://github.com/earendil-works/pi)
- [`hylo-lang/hylo-new`](https://github.com/hylo-lang/hylo-new)
- [`jfernandez/bpftop`](https://github.com/jfernandez/bpftop)
- [`modem-dev/hunk`](https://github.com/modem-dev/hunk)
- [`npm/cli`](https://github.com/npm/cli)
- [`racket/racket/minimal`](https://github.com/racket/racket)
- [`slackapi/slack-cli`](https://github.com/slackapi/slack-cli)
- [`vectordotdev/vector`](https://github.com/vectordotdev/vector)
- [`wasilibs/go-yamllint`](https://github.com/wasilibs/go-yamllint)

### Updated Packages (10)

- [`DataDog/pup`](https://github.com/DataDog/pup)
- [`aquasecurity/trivy`](https://github.com/aquasecurity/trivy)
- [`astral-sh/uv`](https://github.com/astral-sh/uv)
- [`caarlos0/svu`](https://github.com/caarlos0/svu)
-
[`cargo-bins/cargo-binstall`](https://github.com/cargo-bins/cargo-binstall)
- [`foundry-rs/foundry`](https://github.com/foundry-rs/foundry)
- [`gastownhall/beads`](https://github.com/gastownhall/beads)
-
[`gruntwork-io/terragrunt`](https://github.com/gruntwork-io/terragrunt)
- [`pnpm/pnpm`](https://github.com/pnpm/pnpm)
- [`santosr2/TerraTidy`](https://github.com/santosr2/TerraTidy)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant