From 178c72238e7b5bf91895a9917b947216f8be410a Mon Sep 17 00:00:00 2001 From: velaraptor-runpod Date: Thu, 30 Apr 2026 17:49:09 -0500 Subject: [PATCH] fix: surface LORA_MODULES parse failures instead of silently loading zero adapters Fixes FDE-194. Previously a malformed LORA_MODULES value was swallowed at info level and the engine would start with no LoRA adapters, causing 500s on any request using an adapter model name (e.g. npc-sim-*). Changes: - Log at error level when LORA_MODULES cannot be parsed as JSON - Log at error level when individual adapter dicts fail LoRAModulePath validation - Log a final error when all adapters fail to load so the cause is obvious - Accept a single adapter dict (not just an array) for convenience - Return early when LORA_MODULES is unset to skip unnecessary parsing Co-Authored-By: Claude Sonnet 4.6 --- src/engine.py | 49 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/engine.py b/src/engine.py index dcbf67a..80bf72b 100644 --- a/src/engine.py +++ b/src/engine.py @@ -206,19 +206,48 @@ class OpenAIvLLMEngine(vLLMEngine): self.raw_openai_output = bool(int(raw_output_env)) def _load_lora_adapters(self): - adapters = [] - try: - adapters = json.loads(os.getenv("LORA_MODULES", '[]')) - except Exception as e: - logging.info(f"---Initialized adapter json load error: {e}") + lora_modules_env = os.getenv("LORA_MODULES", "") + if not lora_modules_env: + return [] - for i, adapter in enumerate(adapters): + try: + parsed = json.loads(lora_modules_env) + except json.JSONDecodeError as e: + logging.error( + "LORA_MODULES could not be parsed as JSON: %s — no LoRA adapters loaded. Value: %r", + e, lora_modules_env, + ) + return [] + + # Accept a single adapter dict as well as an array + if isinstance(parsed, dict): + parsed = [parsed] + + if not isinstance(parsed, list): + logging.error( + "LORA_MODULES must be a JSON array of adapter objects, got %s — no LoRA adapters loaded.", + type(parsed).__name__, + ) + return [] + + adapters = [] + for i, adapter in enumerate(parsed): try: - adapters[i] = LoRAModulePath(**adapter) - logging.info(f"---Initialized adapter: {adapter}") + adapters.append(LoRAModulePath(**adapter)) + logging.info("Loaded LoRA adapter config [%d]: %s", i, adapter) except Exception as e: - logging.info(f"---Initialized adapter not worked: {e}") - continue + logging.error( + "Failed to parse LoRA adapter at index %d: %s. Config: %r", + i, e, adapter, + ) + + if parsed and not adapters: + logging.error( + "LORA_MODULES specified %d adapter(s) but none could be loaded — " + "OpenAI model name lookups for LoRA adapters will fail.", + len(parsed), + ) + return adapters async def _ensure_engines_initialized(self):