{"record":{"id":"5aa685095ee97e56","repo":"abi/screenshot-to-code","slug":"unreadable-briefs-json-for-set-name-exc","errorCode":null,"errorMessage":"Unreadable briefs.json for {set_name}: {exc}","messagePattern":"Unreadable briefs\\.json for (.+?): (.+?)","errorType":"exception","errorClass":"EvalSetNotFoundError","httpStatus":null,"severity":"error","filePath":"backend/evals/sets.py","lineNumber":106,"sourceCode":"_BRIEF_ID_PATTERN = re.compile(r\"^[a-z0-9][a-z0-9-]*$\")\n\n\ndef get_set_kind(set_name: str) -> str:\n    \"\"\"\"text\" when the set is a briefs.json collection, else \"image\".\"\"\"\n    if os.path.isfile(_briefs_path(set_name)):\n        return \"text\"\n    return \"image\"\n\n\ndef list_set_briefs(set_name: str) -> list[EvalSetBrief]:\n    path = _briefs_path(set_name)\n    if not os.path.isfile(path):\n        raise EvalSetNotFoundError(f\"Text eval set not found: {set_name}\")\n    try:\n        with open(path, \"r\", encoding=\"utf-8\") as f:\n            loaded = cast(dict[str, Any], json.load(f))\n    except (OSError, json.JSONDecodeError) as exc:\n        raise EvalSetNotFoundError(f\"Unreadable briefs.json for {set_name}: {exc}\")\n    briefs: list[EvalSetBrief] = []\n    raw_briefs = loaded.get(\"briefs\")\n    entries = (\n        cast(list[object], raw_briefs) if isinstance(raw_briefs, list) else []\n    )\n    for entry in entries:\n        if not isinstance(entry, dict):\n            continue\n        record = cast(dict[str, Any], entry)\n        brief_id = str(record.get(\"id\") or \"\")\n        brief = str(record.get(\"brief\") or \"\")\n        if not _BRIEF_ID_PATTERN.match(brief_id) or not brief:\n            raise InvalidSetNameError(\n                f\"Invalid brief entry in {set_name}: id={brief_id!r}\"\n            )\n        briefs.append(\n            EvalSetBrief(\n                id=brief_id,","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/abi/screenshot-to-code/blob/d026163f586dfa8c5c10d28c36edd59a9d3b0e88/backend/evals/sets.py#L88-L124","documentation":"EvalSetNotFoundError raised when briefs.json exists but cannot be read or parsed — OSError (permissions, deleted mid-read, I/O error) or json.JSONDecodeError (malformed JSON). The original exception is interpolated into the message so the root cause is visible. It maps 'corrupted file' onto the same not-found semantics: the briefs are unusable either way.","triggerScenarios":"briefs.json with trailing commas, single quotes, truncation from an interrupted write, BOM/encoding issues, or file permissions denying read to the server process.","commonSituations":"Hand-edited briefs.json with invalid JSON, concurrent writers (set edit + eval read), file synced/uploaded with corruption, or read-only mount.","solutions":["Validate the file: python -m json.tool briefs.json shows the exact parse location.","Fix structure to {\"briefs\": [{\"id\": \"...\", \"brief\": \"...\"}, ...]}.","Check file permissions if OSError: the backend process needs read access.","Write briefs.json atomically (temp file + rename) when generating it programmatically."],"exampleFix":"// before\n{ 'briefs': [ { id: 'a1', brief: 'landing page' } ] }\n\n// after\n{\n  \"briefs\": [\n    { \"id\": \"a1\", \"brief\": \"landing page\" }\n  ]\n}","handlingStrategy":"validation","validationCode":"import json, pathlib\ndef briefs_loadable(path: str) -> bool:\n    p = pathlib.Path(path)\n    if not p.is_file():\n        return False\n    try:\n        json.loads(p.read_text(encoding=\"utf-8\"))\n        return True\n    except (OSError, json.JSONDecodeError):\n        return False","typeGuard":"import json\n\ndef is_valid_briefs_payload(data: unknown) -> data is {\"briefs\": list}:\n    return (\n        typeof data === \"object\" and data !== null and\n        Array.isArray((data as any).briefs)\n    );","tryCatchPattern":"try:\n    briefs = list_set_briefs(set_name)\nexcept EvalSetNotFoundError as e:\n    log.warning(\"briefs.json problem for %s: %s\", set_name, e)\n    return HTTPException(status_code=422, detail=f\"Corrupt briefs.json: {e}\")","preventionTips":["Write briefs.json atomically (temp file + os.replace) so interrupted edits never leave truncation.","Run python -m json.tool on hand-edited briefs files before saving.","Validate the {\"briefs\": [...]} schema at creation time, not read time."],"tags":["json","evals","filesystem","corruption"],"backgroundTag":null,"analyzedSha":"d026163f586dfa8c5c10d28c36edd59a9d3b0e88","analyzedAt":"2026-08-14T22:02:06.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}