A config that is perfectly valid JSON but has a server whose value isn't an object blows up:
'not-a-dict' -> ValueError: dictionary update sequence element #0 has length 1; 2 is required
123 -> TypeError: 'int' object is not iterable
['a', 'b'] -> ValueError: dictionary update sequence element #0 has length 1; 2 is required
None -> TypeError: 'NoneType' object is not iterable
(Reproduced against cd2ac2f.)
Why it's a crash, not a handled error
In MainWindow._load_profile, the try/except only wraps the parse. Strict parse succeeds here — the JSON is well-formed — so the repair path is never entered, and core.extract_servers(self.full_config) (bcc.py ~L1944) runs outside any handler. Result: unhandled traceback, and self.current_profile has already been assigned while self.servers has not — the window is left in a half-loaded state.
lint_server() already has the right warnings for malformed shapes, but it can never fire on this class of problem: the load crashes before lint ever sees the entry. The structural-lint feature is unreachable for the single most-likely hand-edit mistake.
This also cuts against the project's core premise — a file that is valid JSON but structurally off should be reported and repaired, never a hard failure.
Suggested fix
Guard in extract_servers: coerce non-dict values to {} (or keep the raw value on the entry) rather than calling dict() on them, and let lint_server surface the warning.
Add a lint_server branch for "server definition is not an object" so the user gets told which entry is malformed.
Move extract_servers inside the load try/except as defence in depth.
Round-trip test: a malformed entry must not be silently dropped on Save (preserve-as-is is fine, silent deletion is not).
Tests
{"mcpServers": {"foo": "not-a-dict"}} and the int/list/None variants load without raising and produce a lint warning naming foo.
## What
`extract_servers()` does `dict(data)` on every server value without checking the shape:
```python
for name, data in (cfg.get("mcpServers") or {}).items():
out.append(ServerEntry(name=name, data=dict(data), enabled=True))
```
A config that is **perfectly valid JSON** but has a server whose value isn't an object blows up:
```
'not-a-dict' -> ValueError: dictionary update sequence element #0 has length 1; 2 is required
123 -> TypeError: 'int' object is not iterable
['a', 'b'] -> ValueError: dictionary update sequence element #0 has length 1; 2 is required
None -> TypeError: 'NoneType' object is not iterable
```
(Reproduced against `cd2ac2f`.)
## Why it's a crash, not a handled error
In `MainWindow._load_profile`, the `try/except` only wraps the parse. Strict parse **succeeds** here — the JSON is well-formed — so the repair path is never entered, and `core.extract_servers(self.full_config)` (bcc.py ~L1944) runs outside any handler. Result: unhandled traceback, and `self.current_profile` has already been assigned while `self.servers` has not — the window is left in a half-loaded state.
## Why it also defeats #54
`lint_server()` already has the right warnings for malformed shapes, but it can never fire on this class of problem: the load crashes before lint ever sees the entry. The structural-lint feature is unreachable for the single most-likely hand-edit mistake.
This also cuts against the project's core premise — a file that is valid JSON but structurally off should be *reported and repaired*, never a hard failure.
## Suggested fix
- Guard in `extract_servers`: coerce non-dict values to `{}` (or keep the raw value on the entry) rather than calling `dict()` on them, and let `lint_server` surface the warning.
- Add a `lint_server` branch for "server definition is not an object" so the user gets told which entry is malformed.
- Move `extract_servers` inside the load try/except as defence in depth.
- Round-trip test: a malformed entry must not be silently dropped on Save (preserve-as-is is fine, silent deletion is not).
## Tests
`{"mcpServers": {"foo": "not-a-dict"}}` and the int/list/None variants load without raising and produce a lint warning naming `foo`.
the_og
added the P1 label 2026-07-20 12:06:58 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
extract_servers()doesdict(data)on every server value without checking the shape:A config that is perfectly valid JSON but has a server whose value isn't an object blows up:
(Reproduced against
cd2ac2f.)Why it's a crash, not a handled error
In
MainWindow._load_profile, thetry/exceptonly wraps the parse. Strict parse succeeds here — the JSON is well-formed — so the repair path is never entered, andcore.extract_servers(self.full_config)(bcc.py ~L1944) runs outside any handler. Result: unhandled traceback, andself.current_profilehas already been assigned whileself.servershas not — the window is left in a half-loaded state.Why it also defeats #54
lint_server()already has the right warnings for malformed shapes, but it can never fire on this class of problem: the load crashes before lint ever sees the entry. The structural-lint feature is unreachable for the single most-likely hand-edit mistake.This also cuts against the project's core premise — a file that is valid JSON but structurally off should be reported and repaired, never a hard failure.
Suggested fix
extract_servers: coerce non-dict values to{}(or keep the raw value on the entry) rather than callingdict()on them, and letlint_serversurface the warning.lint_serverbranch for "server definition is not an object" so the user gets told which entry is malformed.extract_serversinside the load try/except as defence in depth.Tests
{"mcpServers": {"foo": "not-a-dict"}}and the int/list/None variants load without raising and produce a lint warning namingfoo.the_og referenced this issue2026-08-03 22:41:02 -04:00