fix(cli): surface a clean error on an empty or corrupt autoroute config

A configure run killed between secure_create's O_TRUNC and the write
completing leaves an empty config.yaml on disk. The next up read that
via yaml.safe_load (None) into the generated-config TypeAdapter
uncaught, surfacing a raw pydantic.ValidationError instead of pointing
the user back at `lite autoroute configure`.
This commit is contained in:
Krrish Dholakia 2026-07-15 15:05:44 -07:00
parent 3d967b536c
commit eb240d864c
2 changed files with 20 additions and 2 deletions

View file

@ -7,7 +7,7 @@ from types import FrameType
import click
import yaml
from pydantic import JsonValue, TypeAdapter
from pydantic import JsonValue, TypeAdapter, ValidationError
from ..up import CLAUDE_SETTINGS_PATH, load_json_or_empty, restore_claude_settings, write_backup
from ..up import BackupRecord as ClaudeBackupRecord
@ -46,7 +46,12 @@ def _mint_and_embed_master_key() -> str:
"""
master_key = secrets.token_urlsafe(32)
with open(CONFIG_PATH, "r") as f:
generated = _GENERATED_CONFIG_ADAPTER.validate_python(yaml.safe_load(f))
try:
generated = _GENERATED_CONFIG_ADAPTER.validate_python(yaml.safe_load(f))
except (yaml.YAMLError, ValidationError):
raise click.ClickException(
f"{CONFIG_PATH} is empty or corrupt. Run `lite autoroute configure` again to regenerate it."
)
general_settings = generated.get("general_settings")
updated_settings: dict[str, JsonValue] = {
**(general_settings if isinstance(general_settings, dict) else {}),

View file

@ -56,6 +56,19 @@ class TestUpCommand:
assert result.exit_code != 0
assert "lite autoroute configure" in result.output
def test_surfaces_clean_error_on_empty_config_file(self, monkeypatch, tmp_path):
"""A `configure` killed between secure_create's O_TRUNC and the write completing leaves an
empty config.yaml on disk -- yaml.safe_load(empty) returns None, and validating None as the
generated-config model raises a raw pydantic.ValidationError if uncaught."""
config_path, _log_path, _settings_path, _backup_path, _pid_record_path = _patch_paths(monkeypatch, tmp_path)
config_path.write_text("")
result = self.runner.invoke(up)
assert result.exit_code != 0
assert result.exception is None or isinstance(result.exception, SystemExit)
assert "lite autoroute configure" in result.output
def test_refuses_when_pid_record_exists_and_process_still_running(self, monkeypatch, tmp_path):
config_path, _log_path, _settings_path, _backup_path, pid_record_path = _patch_paths(monkeypatch, tmp_path)
config_path.write_text(yaml.safe_dump({"model_list": []}))