config: fix UTF-8 decode crash + null config-value TypeError on Windows (doctor/resource_plan) (#184)
Two related crash bugs in the Python planning layer:
P1: Path.read_text() without encoding= defaults to locale.getpreferredencoding()
(cp1252 on most Windows installs). HuggingFace config.json is UTF-8 — if it
contains any non-ASCII byte (Chinese fields, accented chars, emoji in
metadata), read_text() raises UnicodeDecodeError. In doctor.py this is
caught and mis-reported as 'config.json is missing or invalid' (false
negative); in build_plan() called directly it is an uncaught crash.
Fixed: read_text(encoding='utf-8') in both resource_plan.py and doctor.py.
P2: int(cfg.get('kv_lora_rank', 0)) crashes with TypeError if the key is
present but null (JSON null). dict.get() returns the default only when
the key is ABSENT; a null value returns None, and int(None) raises
TypeError. The engine validates against malformed configs in C but the
Python planner did not.
Fixed: int(cfg.get(key) or 0) — coerces both missing and null to 0.
Applied to all 8 int(cfg.get(...)) calls in build_plan().
Co-authored-by: woolcoxm <13604288+woolcoxm@users.noreply.github.com>
This commit is contained in:
+1
-1
@@ -48,7 +48,7 @@ def run_doctor(model, ram_gb=0, context=4096, gpu_indices=None, vram_gb=0, *,
|
||||
|
||||
config = model / "config.json"
|
||||
try:
|
||||
valid_config = isinstance(json.loads(config.read_text()), dict)
|
||||
valid_config = isinstance(json.loads(config.read_text(encoding="utf-8")), dict)
|
||||
except (OSError, ValueError):
|
||||
valid_config = False
|
||||
checks.append(_check("model.config", "pass" if valid_config else "fail",
|
||||
|
||||
+7
-7
@@ -39,7 +39,7 @@ def analyze_model(model):
|
||||
config_path = model / "config.json"
|
||||
if not config_path.is_file():
|
||||
raise ValueError(f"missing config.json: {model}")
|
||||
config = json.loads(config_path.read_text())
|
||||
config = json.loads(config_path.read_text(encoding="utf-8"))
|
||||
shards = sorted(model.glob("*.safetensors"))
|
||||
if not shards:
|
||||
raise ValueError(f"no safetensors shards: {model}")
|
||||
@@ -210,15 +210,15 @@ def build_plan(model, ram_gb=0, context=4096, gpu_indices=None, vram_gb=0,
|
||||
if ram_budget < 4 * GB:
|
||||
ram_budget = 8 * GB
|
||||
typical = info["typical_expert_bytes"]
|
||||
layers = int(cfg.get("num_hidden_layers", 0)) + 1
|
||||
kv_bytes = layers * context * (int(cfg.get("kv_lora_rank", 0)) +
|
||||
int(cfg.get("qk_rope_head_dim", 0))) * 4
|
||||
kv_buffer = context * int(cfg.get("num_attention_heads", 0)) * (
|
||||
int(cfg.get("qk_nope_head_dim", 0)) + int(cfg.get("v_head_dim", 0))) * 4
|
||||
layers = int(cfg.get("num_hidden_layers") or 0) + 1
|
||||
kv_bytes = layers * context * (int(cfg.get("kv_lora_rank") or 0) +
|
||||
int(cfg.get("qk_rope_head_dim") or 0)) * 4
|
||||
kv_buffer = context * int(cfg.get("num_attention_heads") or 0) * (
|
||||
int(cfg.get("qk_nope_head_dim") or 0) + int(cfg.get("v_head_dim") or 0)) * 4
|
||||
runtime_bytes = int(1.2 * GB + 2.5 * GB + 64 * typical + kv_bytes + kv_buffer)
|
||||
cache_bytes = max(0, ram_budget - info["dense_bytes"] - runtime_bytes)
|
||||
per_cap = info["per_cap_bytes"]
|
||||
configured_experts = int(cfg.get("n_routed_experts", 0))
|
||||
configured_experts = int(cfg.get("n_routed_experts") or 0)
|
||||
cap = int(cache_bytes // per_cap) if per_cap else 0
|
||||
if configured_experts:
|
||||
cap = min(cap, configured_experts)
|
||||
|
||||
Reference in New Issue
Block a user