{"record":{"id":"29d934de4df50b37","repo":"unslothai/unsloth","slug":"add-a-provider-connection-block-before-running-thi","errorCode":null,"errorMessage":"Add a Provider connection block before running this recipe.","messagePattern":"Add a Provider connection block before running this recipe\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/data_recipe/service.py","lineNumber":166,"sourceCode":"            )\n        )\n\n    return providers\n\n\ndef _recipe_has_llm_columns(recipe: dict[str, Any]) -> bool:\n    for column in recipe.get(\"columns\", []):\n        if not isinstance(column, dict):\n            continue\n        column_type = column.get(\"column_type\")\n        if isinstance(column_type, str) and column_type.startswith(\"llm-\"):\n            return True\n    return False\n\n\ndef _validate_recipe_runtime_support(recipe: dict[str, Any], model_providers: list[Any]) -> None:\n    if _recipe_has_llm_columns(recipe) and not model_providers:\n        raise ValueError(\"Add a Provider connection block before running this recipe.\")\n\n\ndef recipe_has_stdio_mcp(recipe: dict[str, Any]) -> bool:\n    \"\"\"True when the recipe asks for a local (stdio) MCP provider, i.e. a command\n    this host would run. Routes gate on it to keep that behind a UI session.\"\"\"\n    providers = recipe.get(\"mcp_providers\") or []\n    if not isinstance(providers, list):\n        return False\n    return any(\n        isinstance(provider, dict) and provider.get(\"provider_type\") == \"stdio\"\n        for provider in providers\n    )\n\n\ndef build_mcp_providers(recipe: dict[str, Any]) -> list:\n    from data_designer.config.mcp import LocalStdioMCPProvider, MCPProvider  # pyright: ignore[reportMissingImports]\n\n    # Same gate as the chat MCP path: stdio providers spawn a local subprocess,","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/data_recipe/service.py#L148-L184","documentation":"ValueError raised by _validate_recipe_runtime_support when a recipe declares at least one LLM column (column_type starting with 'llm-') but the model_providers list is empty. LLM columns need a configured model provider connection to execute; with none, the recipe cannot run, so validation fails fast before a job is spawned.","triggerScenarios":"Submitting a recipe with columns whose column_type is e.g. 'llm-judge' or 'llm-generate' while no Provider connection blocks exist in the runtime; providers configured at the workspace level but not passed into the run request; deleting/disconnecting all providers then re-running an old recipe.","commonSituations":"New users building their first recipe with an LLM column without adding a Provider connection; provider tokens revoked or connections removed after the recipe was authored; API callers constructing run payloads that omit providers.","solutions":["Add a Provider connection block (API key/endpoint for the model backend) in the recipe or workspace settings, then re-run.","If calling the API programmatically, include the configured model providers in the run payload.","Or remove/replace the LLM columns if no LLM generation is intended."],"exampleFix":"# before\nrecipe = {\"columns\": [{\"column_type\": \"llm-generate\", \"prompt\": \"...\"}]}\nrun_recipe(recipe, model_providers=[])\n\n# after\nrecipe = {\n    \"columns\": [{\"column_type\": \"llm-generate\", \"prompt\": \"...\"}],\n    \"mcp_providers\": [],\n}\nrun_recipe(recipe, model_providers=[{\"name\": \"openai\", \"api_key\": os.environ['OPENAI_API_KEY']}])","handlingStrategy":"validation","validationCode":"def recipe_has_llm_columns(recipe):\n    return any(\n        isinstance(c, dict) and isinstance(c.get('column_type'), str) and c['column_type'].startswith('llm-')\n        for c in recipe.get('columns', [])\n    )\nassert not (recipe_has_llm_columns(recipe) and not model_providers), 'add a Provider connection first'","typeGuard":"def recipe_has_llm_columns(recipe: dict) -> bool: ...  # as above; use to branch UI/validation","tryCatchPattern":"try:\n    run_recipe(recipe, model_providers=providers)\nexcept ValueError as e:\n    if 'Provider connection' in str(e):\n        prompt_user_to_add_provider(); return","preventionTips":["Validate LLM-column vs provider presence client-side before submit.","Keep provider connections configured at the workspace level so recipes inherit them.","Re-check provider connections after revoking or rotating keys."],"tags":["validation","configuration","llm","data-recipe","studio"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}