{"record":{"id":"7596224e5ea6d9d1","repo":"abi/screenshot-to-code","slug":"at-least-one-model-is-required","errorCode":null,"errorMessage":"At least one model is required","messagePattern":"At least one model is required","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"backend/routes/evals.py","lineNumber":267,"sourceCode":"        if selected_files:\n            return len([f for f in selected_files if f in brief_ids])\n        return len(brief_ids)\n\n    if selected_files:\n        return len([f for f in selected_files if f.endswith(\".png\")])\n\n    if set_name:\n        return len(eval_sets.list_set_images(set_name))\n\n    input_dir = os.path.join(EVALS_DIR, \"inputs\")\n    return len([f for f in os.listdir(input_dir) if f.endswith(\".png\")])\n\n\n@router.post(\"/run_evals_stream\")\nasync def run_evals_stream(request: RunEvalsRequest):\n    \"\"\"Run evaluations and stream progress events as newline-delimited JSON.\"\"\"\n    if not request.models:\n        raise HTTPException(status_code=400, detail=\"At least one model is required\")\n\n    eval_set, session, skip_per_model = _resolve_set_run(request)\n\n    per_model_task_counts: Dict[str, int] = {}\n    per_model_skipped_existing: Dict[str, int] = {}\n    if request.diff_mode:\n        for model in request.models:\n            pending_tasks, skipped_tasks = count_pending_eval_tasks(\n                stack=request.stack,\n                model=model,\n                input_files=request.files,\n                n=N,\n                diff_mode=True,\n                eval_set=eval_set,\n                skip_input_files=skip_per_model.get(model),\n            )\n            per_model_task_counts[model] = pending_tasks\n            per_model_skipped_existing[model] = skipped_tasks","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/abi/screenshot-to-code/blob/d026163f586dfa8c5c10d28c36edd59a9d3b0e88/backend/routes/evals.py#L249-L285","documentation":"400 raised by POST /run_evals_stream in backend/routes/evals.py:267 when the request body's models list is empty. At least one model must be selected to schedule evaluation tasks; the guard fires before any set/session resolution.","triggerScenarios":"POST /run_evals_stream with models: [] — e.g. the UI sent the request before any model checkbox was ticked, or a filter removed all models.","commonSituations":"Default model list empty due to missing API keys filtering out all models; race where the run button is enabled before model selection loads.","solutions":["Include at least one valid model name in the models array.","Disable the run button in the UI until at least one model is selected.","If no models appear selectable, check that an API key is configured (see the models the backend offers)."],"exampleFix":"// before\nif (runRequested) startRun({ models: selectedModels, ... });\n\n// after\nif (selectedModels.length === 0) { toast('Select at least one model'); return; }\nstartRun({ models: selectedModels, ... });","handlingStrategy":"validation","validationCode":"if (!Array.isArray(models) || models.length === 0) {\n  throw new Error('At least one model is required');\n}","typeGuard":"function hasModels(models: unknown): models is string[] {\n  return Array.isArray(models) && models.length > 0 && models.every(m => typeof m === 'string');\n}","tryCatchPattern":null,"preventionTips":["Keep the run button disabled until a model is selected.","If the model list is empty, check API-key configuration first."],"tags":["http-400","validation","evals","fastapi"],"backgroundTag":null,"analyzedSha":"d026163f586dfa8c5c10d28c36edd59a9d3b0e88","analyzedAt":"2026-08-14T22:02:06.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}