{"record":{"id":"d15f33ea5bad4cab","repo":"abi/screenshot-to-code","slug":"not-a-set-image-filename-r","errorCode":null,"errorMessage":"Not a set image: {filename!r}","messagePattern":"Not a set image: (.+?)","errorType":"exception","errorClass":"InvalidSetNameError","httpStatus":null,"severity":"error","filePath":"backend/evals/sets.py","lineNumber":297,"sourceCode":"            continue\n        set_dir = os.path.join(sets_dir, entry)\n        if not (\n            os.path.isdir(os.path.join(set_dir, \"inputs\"))\n            or os.path.isfile(os.path.join(set_dir, \"briefs.json\"))\n        ):\n            continue\n        infos.append(get_set(entry))\n    return infos\n\n\ndef resolve_set_image_path(set_name: str, filename: str) -> str:\n    \"\"\"Absolute path of a set image; raises on traversal or missing file.\"\"\"\n    inputs_dir = get_set_inputs_dir(set_name)\n    if not os.path.isdir(inputs_dir):\n        raise EvalSetNotFoundError(f\"Eval set not found: {set_name}\")\n    safe_name = os.path.basename(filename)\n    if not safe_name.lower().endswith(\".png\"):\n        raise InvalidSetNameError(f\"Not a set image: {filename!r}\")\n    path = os.path.realpath(os.path.join(inputs_dir, safe_name))\n    if not path.startswith(os.path.realpath(inputs_dir) + os.sep):\n        raise InvalidSetNameError(f\"Invalid image path: {filename!r}\")\n    if not os.path.isfile(path):\n        raise FileNotFoundError(path)\n    return path\n","sourceCodeStart":279,"sourceCodeEnd":304,"githubUrl":"https://github.com/abi/screenshot-to-code/blob/d026163f586dfa8c5c10d28c36edd59a9d3b0e88/backend/evals/sets.py#L279-L304","documentation":"resolve_set_image_path raises InvalidSetNameError(\"Not a set image\") when the filename (after basename normalization) does not end in .png. The function only serves PNG files from a set's inputs directory, so JPG/WEBP/JSON or extension-less filenames are rejected before any filesystem access. basename() is applied first, so path components never reach this check — only the final extension matters.","triggerScenarios":"Calling resolve_set_image_path(name, \"shot.jpg\"), \"manifest.json\", \"image\" (no extension), or a URL like \"/images/shot.png?raw\" where the query string survives into the filename. Case is handled (.PNG passes), so only genuinely non-PNG suffixes trigger it.","commonSituations":"Frontend building image URLs from files that are not PNG; a set folder accidentally containing .jpg screenshots the user expects to serve; typos or missing extensions in hardcoded URLs.","solutions":["Convert non-PNG inputs to PNG before dropping them into inputs/ (only PNGs are supported).","Fix the requested filename to end with .png (any casing).","On the caller side, filter filenames with filename.lower().endswith('.png') before resolving."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"def is_png_filename(filename: str) -> bool:\n    return os.path.basename(filename).lower().endswith(\".png\")","typeGuard":"def is_set_image_filename(filename: str) -> bool:\n    \"\"\"True when resolve_set_image_path will accept the filename.\"\"\"\n    return bool(filename) and os.path.basename(filename).lower().endswith(\".png\")","tryCatchPattern":"try:\n    path = resolve_set_image_path(set_name, filename)\nexcept InvalidSetNameError:\n    abort(400, description=\"only .png set images are served\")","preventionTips":["Convert all set inputs to PNG at authoring time","Filter URL builders on .lower().endswith('.png')","Strip query strings from filenames before resolving"],"tags":["evals","validation","file-type","png"],"backgroundTag":null,"analyzedSha":"d026163f586dfa8c5c10d28c36edd59a9d3b0e88","analyzedAt":"2026-08-14T22:02:06.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}