You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
`gitt config set` (gittensor/cli/main.py:117-138) prints a yellow warning when it cannot parse the existing `~/.gittensor/config.json`, then silently overwrites the file with only the new key, losing every previously-configured value:
```python
config = {}
if CONFIG_FILE.exists():
try:
config = json.loads(CONFIG_FILE.read_text())
except json.JSONDecodeError:
console.print('[yellow]Warning: Existing config was invalid, starting fresh[/yellow]')
This is the write-side counterpart to #816 ("`load_config` silently swallows JSONDecodeError"). #816 / PR #817 fix the read paths so commands stop silently retargeting mainnet, but `config_set` still happily clobbers the only on-disk record. After a single corrupt-config recovery, the operator's `network` / `contract_address` / `hotkey` / `ws_endpoint` are gone and the next `gitt issues …` command falls through to finney mainnet defaults.
This is the same family as #781 (`pat_storage._read_file` returning `[]` and the next `save_pat` overwriting the corrupt file) — a write-path that interprets "unparsable" as "empty" instead of "refuse to overwrite".
Steps to Reproduce
`gitt config set network test`
`gitt config set contract_address 5XYZ...`
`gitt config set wallet alice` ← three keys committed.
Corrupt the file (simulating a partial write from a crashed process):
`echo '{"network": "test"' > ~/.gittensor/config.json`
`gitt config set hotkey default`
`cat ~/.gittensor/config.json` → `{"hotkey": "default"}`. The other three keys are gone.
Expected Behavior
Refuse to overwrite a corrupt config file. Either:
Atomically move the corrupt file aside (e.g. `config.json.corrupt.`) before writing fresh.
Either way, the operator's previously-set keys must survive a single corrupt-file event.
Actual Behavior
The yellow "Warning: Existing config was invalid, starting fresh" message is printed, but `config = {}` is the actual default, and the subsequent `CONFIG_FILE.write_text(json.dumps(config, indent=2))` writes a fresh single-entry config to disk, losing every other key.
Impact
Silent data loss of operator config — `network`, `contract_address`, `ws_endpoint` may all disappear. The next `gitt issues …` runs on finney mainnet against the hardcoded contract instead of the operator's intended target.
Frequency: corrupt JSON files are caused by interrupted writes (`Ctrl-C` mid-`gitt config set`), simultaneous edits, on-disk corruption, or accidental manual edits — none rare.
Suggested fix
Mirror PR #817: turn the JSONDecodeError branch into an error + `SystemExit(1)`. The yellow warning + write-anyway path must go away. A regression test under a new `TestConfigSetCorruption` class in `tests/cli/test_config_set.py` (alongside #813) can pin both the exit code and the on-disk preservation invariant.
Description
`gitt config set` (gittensor/cli/main.py:117-138) prints a yellow warning when it cannot parse the existing `~/.gittensor/config.json`, then silently overwrites the file with only the new key, losing every previously-configured value:
```python
config = {}
if CONFIG_FILE.exists():
try:
config = json.loads(CONFIG_FILE.read_text())
except json.JSONDecodeError:
console.print('[yellow]Warning: Existing config was invalid, starting fresh[/yellow]')
Set the value
old_value = config.get(key)
config[key] = value
Write config
CONFIG_FILE.write_text(json.dumps(config, indent=2))
```
This is the write-side counterpart to #816 ("`load_config` silently swallows JSONDecodeError"). #816 / PR #817 fix the read paths so commands stop silently retargeting mainnet, but `config_set` still happily clobbers the only on-disk record. After a single corrupt-config recovery, the operator's `network` / `contract_address` / `hotkey` / `ws_endpoint` are gone and the next `gitt issues …` command falls through to finney mainnet defaults.
This is the same family as #781 (`pat_storage._read_file` returning `[]` and the next `save_pat` overwriting the corrupt file) — a write-path that interprets "unparsable" as "empty" instead of "refuse to overwrite".
Steps to Reproduce
`echo '{"network": "test"' > ~/.gittensor/config.json`
Expected Behavior
Refuse to overwrite a corrupt config file. Either:
Either way, the operator's previously-set keys must survive a single corrupt-file event.
Actual Behavior
The yellow "Warning: Existing config was invalid, starting fresh" message is printed, but `config = {}` is the actual default, and the subsequent `CONFIG_FILE.write_text(json.dumps(config, indent=2))` writes a fresh single-entry config to disk, losing every other key.
Impact
Suggested fix
Mirror PR #817: turn the JSONDecodeError branch into an error + `SystemExit(1)`. The yellow warning + write-anyway path must go away. A regression test under a new `TestConfigSetCorruption` class in `tests/cli/test_config_set.py` (alongside #813) can pin both the exit code and the on-disk preservation invariant.