diff --git a/py/lora_manager_layout.py b/py/lora_manager_layout.py index 36f2fada..d05abe59 100644 --- a/py/lora_manager_layout.py +++ b/py/lora_manager_layout.py @@ -577,7 +577,7 @@ def _preview_candidates(sidecar: Sidecar, metadata: Dict) -> Iterator[str]: # LoraManager writes absolute paths; it would resolve a relative # one against its working directory, not the sidecar folder. logger.debug( - f"Relative preview_url skipped in {sidecar.metadata_path.name}" + "Relative preview_url skipped in %s", sidecar.metadata_path.name ) base = sidecar.metadata_path.name[: -len(METADATA_SUFFIX)] for suffix in PREVIEW_EXTENSIONS: diff --git a/py/lora_utils.py b/py/lora_utils.py index dc0722fe..da71a3c9 100644 --- a/py/lora_utils.py +++ b/py/lora_utils.py @@ -368,7 +368,7 @@ def read_lora_metadata(metadata_path: Path) -> Optional[Dict]: try: with open(metadata_path, "r", encoding="utf-8") as f: return json.load(f) - except (json.JSONDecodeError, OSError) as e: + except (ValueError, OSError) as e: # JSONDecodeError, UnicodeDecodeError logger.debug(f"Failed to read {metadata_path}: {e}") return None diff --git a/tests/test_api_images.py b/tests/test_api_images.py index b65ae766..08713ddb 100644 --- a/tests/test_api_images.py +++ b/tests/test_api_images.py @@ -1534,12 +1534,10 @@ class TestLoraManagerMediaServing(ImageRouteCoverageCase): self.assertEqual(await self._status(self._link_image(self._example())), 200) self.assertIsNotNone(lora_utils._layout_cache._entry) - stored = lora_utils._layout_cache._entry with patch.object(IntegrationConfig, "LORA_MANAGER_PATH", str(self.sidecars)): self.assertEqual(self.api._lora_image_dirs(), []) # The warm entry for the real install was never handed out for it. self.assertIsNone(lora_utils.cached_lora_manager_layout(str(self.sidecars))[0]) - self.assertIsNotNone(stored) async def test_serve_image_builds_the_allow_list_in_the_executor(self): calls = self._spy_executor() diff --git a/tests/test_lora_layout_cache.py b/tests/test_lora_layout_cache.py index 49eff089..e1287ba4 100644 --- a/tests/test_lora_layout_cache.py +++ b/tests/test_lora_layout_cache.py @@ -15,8 +15,8 @@ import tempfile import threading import time import unittest -from pathlib import Path, PureWindowsPath from dataclasses import replace +from pathlib import Path, PureWindowsPath from types import SimpleNamespace from unittest.mock import patch diff --git a/tests/test_lora_utils.py b/tests/test_lora_utils.py index 1a68ed0a..d271c771 100644 --- a/tests/test_lora_utils.py +++ b/tests/test_lora_utils.py @@ -224,6 +224,14 @@ class TestReadLoraMetadata(unittest.TestCase): result = read_lora_metadata(Path("/nonexistent/file.metadata.json")) self.assertIsNone(result) + def test_returns_none_for_a_file_that_is_not_utf8(self): + # #362: one malformed sidecar is skipped; it must not fail the whole + # trigger-word load (now logged with a traceback) or the review. + with tempfile.TemporaryDirectory() as folder: + path = Path(folder) / "bad.metadata.json" + path.write_bytes(b'{"model_name": "\xff\xfe"}') + self.assertIsNone(read_lora_metadata(path)) + class TestGetLoraImageCacheDir(unittest.TestCase): """Test get_lora_image_cache_dir — returns and creates cache path."""