{"record":{"id":"ef026d5a825b6c7d","repo":"Graphify-Labs/graphify","slug":"unknown-backend-backend-r","errorCode":null,"errorMessage":"Unknown backend {backend!r}","messagePattern":"Unknown backend (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"graphify/llm.py","lineNumber":2573,"sourceCode":") -> str:\n    \"\"\"Send a plain-text prompt to `backend` and return the model's text reply.\n\n    When ``usage_out`` is provided it is accumulated in place with ``input`` and\n    ``output`` token counts from the response, so callers (community labeling)\n    can total the cost of otherwise-uninstrumented LLM calls (#1694). Existing\n    callers that omit it are unaffected.\n\n    Used by lightweight callers (e.g. `graphify.dedup` LLM tiebreaker) that\n    don't need the full extraction prompt or JSON-shaped output. Mirrors the\n    backend dispatch logic of `extract_files_direct` but skips the\n    `_EXTRACTION_SYSTEM` prompt and JSON parsing.\n\n    Previously `graphify.dedup` imported a `_call_llm` symbol that did not\n    exist in this module, so the LLM tiebreaker silently no-op'd on\n    `ImportError` (F-038). Adding the function here re-enables it.\n    \"\"\"\n    if backend not in BACKENDS:\n        raise ValueError(f\"Unknown backend {backend!r}\")\n    cfg = BACKENDS[backend]\n    key = _get_backend_api_key(backend)\n    if not key and backend == \"ollama\":\n        ollama_url = _resolve_ollama_base_url(cfg.get(\"base_url\", \"\"))\n        _validate_ollama_base_url(ollama_url)\n        key = \"ollama\"\n    if not key and backend not in (\"bedrock\", \"claude-cli\"):\n        raise ValueError(\n            f\"No API key for backend '{backend}'. Set {_format_backend_env_keys(backend)}.\"\n        )\n    mdl = model or _default_model_for_backend(backend)\n\n    def _rec(inp, out) -> None:\n        if usage_out is not None:\n            usage_out[\"input\"] = usage_out.get(\"input\", 0) + int(inp or 0)\n            usage_out[\"output\"] = usage_out.get(\"output\", 0) + int(out or 0)\n\n    if backend == \"claude\":","sourceCodeStart":2555,"sourceCodeEnd":2591,"githubUrl":"https://github.com/Graphify-Labs/graphify/blob/7fe58b0b0f3873be9a21c30106b8b8527c353aa6/graphify/llm.py#L2555-L2591","documentation":"Raised by the lightweight `call_llm` helper (used e.g. by `graphify.dedup`'s LLM tiebreaker) when the given `backend` string is not in the `BACKENDS` registry. It mirrors `extract_files_direct`'s dispatch validation (error 54) but for callers that don't need the extraction prompt/JSON parsing. Unlike error 54 it doesn't list available names in the message.","triggerScenarios":"Calling `call_llm(prompt, backend=\"gpt\")`, `call_llm(..., backend=\"Azure\")`, or any unregistered/case-mismatched name; passing a provider label read from user config without validating it against BACKENDS.","commonSituations":"Free-text backend fields in user configs; typos; assuming a provider alias works; code written against a newer graphify that added backends, run on an older install lacking them.","solutions":["Use a registered backend key — check `from graphify.llm import BACKENDS; sorted(BACKENDS)` for the exact names.","Validate config-supplied backend strings against BACKENDS before calling call_llm.","Upgrade graphify if the backend you want exists only in newer versions."],"exampleFix":"# before\nfrom graphify.llm import call_llm\ncall_llm(\"...\", backend=\"OpenAI\")\n\n# after\nfrom graphify.llm import call_llm, BACKENDS\nbackend = \"openai\" if \"openai\" in BACKENDS else \"gemini\"\ncall_llm(\"...\", backend=backend)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"from graphify.llm import BACKENDS\n\ndef is_known_backend(name: str) -> bool:\n    return isinstance(name, str) and name in BACKENDS\n\nif not is_known_backend(cfg[\"llm_backend\"]):\n    raise ValueError(f\"{cfg['llm_backend']!r} not in {sorted(BACKENDS)}\")","tryCatchPattern":null,"preventionTips":["Validate user/config backend strings against BACKENDS before calling call_llm (used by graphify.dedup's tiebreaker).","Expose the sorted BACKENDS list in your tool's validation error so users self-correct."],"tags":["validation","backend","configuration"],"backgroundTag":null,"analyzedSha":"7fe58b0b0f3873be9a21c30106b8b8527c353aa6","analyzedAt":"2026-08-14T19:23:21.323Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}