{"record":{"id":"79b229dcab49d920","repo":"abi/screenshot-to-code","slug":"not-a-set-image-filename-r-79b229","errorCode":null,"errorMessage":"Not a set image: {filename!r}","messagePattern":"Not a set image: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"backend/routes/eval_sets.py","lineNumber":175,"sourceCode":"        **_set_info_to_model(info).model_dump(),\n        images=[\n            EvalSetImageModel(\n                filename=image.filename,\n                sha256=image.sha256,\n                size_bytes=image.size_bytes,\n                tags=image.tags,\n            )\n            for image in images\n        ],\n    )\n\n\n@router.get(\"/eval-sets/{set_name}/images/{filename}\")\nasync def get_eval_set_image(set_name: str, filename: str) -> FileResponse:\n    try:\n        path = eval_sets.resolve_set_image_path(set_name, filename)\n    except eval_sets.InvalidSetNameError as e:\n        raise HTTPException(status_code=400, detail=str(e))\n    except eval_sets.EvalSetNotFoundError:\n        raise HTTPException(status_code=404, detail=f\"Eval set not found: {set_name}\")\n    except FileNotFoundError:\n        raise HTTPException(status_code=404, detail=\"Image not found\")\n    return FileResponse(path)\n\n\n@router.get(\"/eval-sessions\", response_model=EvalSessionListResponse)\nasync def list_eval_sessions() -> EvalSessionListResponse:\n    sessions = eval_sessions.list_sessions()\n    active = next((s for s in sessions if s.is_active), None)\n    return EvalSessionListResponse(\n        sessions=[_session_to_model(s) for s in sessions],\n        active_session_id=active.session_id if active else None,\n    )\n\n\n@router.get(\"/eval-sessions/active\", response_model=Optional[EvalSessionModel])","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/abi/screenshot-to-code/blob/d026163f586dfa8c5c10d28c36edd59a9d3b0e88/backend/routes/eval_sets.py#L157-L193","documentation":"Raised by evals.sets.resolve_set_image_path() (backend/evals/sets.py:297) and surfaced as 400 by GET /eval-sets/{set_name}/images/{filename}. After basename() stripping, the filename must end in '.png' (case-insensitive); any other extension or bare name is rejected as 'not a set image'. Set images are PNG-only by contract.","triggerScenarios":"GET /eval-sets/{set}/images/{filename} where filename is 'shot.jpg', 'capture.webp', 'manifest.json', or has no extension. Note the check happens before the existence check, so this fires even for non-existent non-PNG names.","commonSituations":"Frontend builds image URLs from filenames with non-PNG extensions; users drop JPGs into the inputs directory expecting them to be served; probing for arbitrary files (e.g. manifest.json) through the image route.","solutions":["Request only .png files that the set actually contains (list them via GET /eval-sets/{set_name}).","Convert non-PNG images to PNG when adding them to a set's inputs directory.","Send the bare filename without directories."],"exampleFix":"# before\nGET /eval-sets/my-set/images/shot.jpg  # 400 'Not a set image'\n\n# after\nGET /eval-sets/my-set/images/shot.png  # PNG files only","handlingStrategy":"validation","validationCode":"import os\n\ndef is_png_filename(filename: str) -> bool:\n    return os.path.basename(filename).lower().endswith(\".png\")\n\nif not is_png_filename(filename):\n    raise ValueError(f\"only .png images are servable: {filename!r}\")","typeGuard":"def is_set_image_name(filename: object) -> bool:\n    return (\n        isinstance(filename, str)\n        and filename == os.path.basename(filename)\n        and filename.lower().endswith(\".png\")\n    )","tryCatchPattern":"resp = requests.get(url + f\"/eval-sets/{set_name}/images/{filename}\")\nif resp.status_code == 400 and \"Not a set image\" in resp.text:\n    raise ValueError(\"images must be bare .png filenames\")\nresp.raise_for_status()","preventionTips":["Store only PNGs in set inputs directories; convert other formats up front.","Build image URLs from filenames returned by the set detail endpoint.","Send bare filenames, no directories."],"tags":["fastapi","http-400","validation","png","eval-sets"],"backgroundTag":null,"analyzedSha":"d026163f586dfa8c5c10d28c36edd59a9d3b0e88","analyzedAt":"2026-08-14T22:02:06.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}