{"record":{"id":"f2b57cca1788be62","repo":"abi/screenshot-to-code","slug":"invalid-eval-set-name-set-name-r","errorCode":null,"errorMessage":"Invalid eval set name: {set_name!r}","messagePattern":"Invalid eval set name: (.+?)","errorType":"exception","errorClass":"InvalidSetNameError","httpStatus":null,"severity":"error","filePath":"backend/evals/sets.py","lineNumber":68,"sourceCode":"\n\n@dataclass\nclass EvalSetInfo:\n    name: str\n    display_name: str\n    created_at: Optional[str]\n    notes: str\n    image_count: int\n    kind: str = \"image\"  # \"image\" | \"text\"\n\n\ndef get_sets_dir() -> str:\n    return os.path.join(evals_config.EVALS_DIR, \"sets\")\n\n\ndef _validate_set_name(set_name: str) -> str:\n    if not _SET_NAME_PATTERN.match(set_name):\n        raise InvalidSetNameError(f\"Invalid eval set name: {set_name!r}\")\n    return set_name\n\n\ndef _get_set_dir(set_name: str) -> str:\n    return os.path.join(get_sets_dir(), _validate_set_name(set_name))\n\n\ndef get_set_inputs_dir(set_name: str) -> str:\n    return os.path.join(_get_set_dir(set_name), \"inputs\")\n\n\ndef _manifest_path(set_name: str) -> str:\n    return os.path.join(_get_set_dir(set_name), \"manifest.json\")\n\n\ndef _briefs_path(set_name: str) -> str:\n    return os.path.join(_get_set_dir(set_name), \"briefs.json\")\n","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/abi/screenshot-to-code/blob/d026163f586dfa8c5c10d28c36edd59a9d3b0e88/backend/evals/sets.py#L50-L86","documentation":"InvalidSetNameError raised by _validate_set_name when the set name fails ^[A-Za-z0-9][A-Za-z0-9._ -]*$ — it must start with an alphanumeric and may then contain letters, digits, dot, underscore, space, and hyphen. The validator fronts _get_set_dir, so any path-building operation on a set (inputs dir, manifest) is protected from path traversal and odd filesystem characters.","triggerScenarios":"Creating or reading a set whose name starts with '.', '/', '-', or a space, contains slashes or '..', or uses non-ASCII characters — e.g. POSTing a name like '../secrets' or 'my set#2'.","commonSituations":"UI allowing free-text set names, API consumers passing URL-decoded paths, or attempts at path traversal (the pattern blocks them).","solutions":["Rename the set to match the pattern: start with a letter/digit, use only [A-Za-z0-9._ -].","Sanitize user input before calling set APIs: strip, replace disallowed characters with '-' or '_'.","Validate client-side in the eval sessions form so the user gets immediate feedback."],"exampleFix":"// before\nconst name = userInput; // \"my set#2\"\n\n// after\nconst name = userInput.trim().replace(/[^A-Za-z0-9._ -]/g, \"-\").replace(/^[. _-]+/, \"\") || \"untitled\";","handlingStrategy":"validation","validationCode":"import re\nSET_NAME = re.compile(r\"^[A-Za-z0-9][A-Za-z0-9._ -]*$\")\ndef valid_set_name(name: str) -> bool:\n    return isinstance(name, str) and bool(SET_NAME.match(name))","typeGuard":"function isValidSetName(name: unknown): name is string {\n  return typeof name === \"string\" && /^[A-Za-z0-9][A-Za-z0-9._ -]*$/.test(name);\n}","tryCatchPattern":"try:\n    _get_set_dir(set_name)\nexcept InvalidSetNameError:\n    return HTTPException(status_code=422, detail=\"Set name must start with a letter/digit\")","preventionTips":["Enforce the same regex in every client that creates set names (frontend form + API consumers).","Never accept raw path fragments as set names — the regex is the traversal guard.","Test set-name validation with '../', leading dots, and unicode inputs."],"tags":["validation","evals","naming","path-safety"],"backgroundTag":null,"analyzedSha":"d026163f586dfa8c5c10d28c36edd59a9d3b0e88","analyzedAt":"2026-08-14T22:02:06.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}