{"record":{"id":"ead949170e3d4d0e","repo":"infiniflow/ragflow","slug":"provider-name-is-required","errorCode":null,"errorMessage":"Provider name is required.","messagePattern":"Provider name is required\\.","errorType":"exception","errorClass":"LookupError","httpStatus":null,"severity":"error","filePath":"api/db/joint_services/tenant_model_service.py","lineNumber":472,"sourceCode":"                \"Direct-ID resolution: instance not found | tenant_id=%s model_id=%s instance_id=%s\",\n                tenant_id,\n                model_name,\n                model_obj.instance_id,\n            )\n            raise LookupError(f\"Instance {model_obj.instance_id} not found for model {model_name}.\")\n        logger.debug(\n            \"Direct-ID resolution: resolved | tenant_id=%s model_id=%s instance_id=%s\",\n            tenant_id,\n            model_name,\n            model_obj.instance_id,\n        )\n        return instance_obj.api_key\n\n    # Fall back to name-based resolution: model[@instance]@provider\n    _, instance_name, provider_name = split_model_name(model_name)\n\n    if not provider_name:\n        raise LookupError(\"Provider name is required.\")\n    provider_obj = TenantModelProviderService.get_by_tenant_id_and_provider_name(tenant_id, provider_name)\n    if not provider_obj:\n        raise LookupError(f\"Provider {provider_name} not found.\")\n    instance_obj = _resolve_instance_for_model(provider_obj, instance_name, model_name)\n    return instance_obj.api_key\n\n\ndef get_model_type_by_id(model_id: str):\n    exist, model_obj = TenantModelService.get_by_id(model_id)\n    if not exist:\n        raise LookupError(f\"TenantModel id={model_id} not found.\")\n    return get_model_type_human(model_obj.model_type)\n\n\ndef resolve_model_type(tenant_id: str, model_ref: str):\n    try:\n        return get_model_type_by_id(model_ref)\n    except LookupError:","sourceCodeStart":454,"sourceCodeEnd":490,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/api/db/joint_services/tenant_model_service.py#L454-L490","documentation":"LookupError raised by get_api_key's name-based fallback path: model_name did not parse as a direct id, and split_model_name found no '@provider' suffix, so there is no way to locate the tenant_model_provider row that holds the API key. Unlike the resolver at line 390, this path has no TEI builtin escape hatch — a provider segment is unconditionally required.","triggerScenarios":"Calling get_api_key(tenant_id, 'gpt-4o') with a bare name (no '@OpenAI'); a model string that is neither an existing tenant_model id nor a 'model@provider' reference; empty provider segment after splitting.","commonSituations":"Configs or env vars storing bare model names; older integrations written before the provider-suffix scheme; values copied from provider dashboards (which show bare names) into RAGFlow settings.","solutions":["Pass the fully qualified 'model@provider' (or 'model@instance@provider') string, e.g. 'BAAI/bge-large-en-v1.5@OpenAI-Compatible'.","Or pass the tenant_model id (UUID) directly — the direct-ID path runs first.","Normalize stored model settings to always carry the provider suffix."],"exampleFix":"# before\nkey = get_api_key(tenant_id, \"deepseek-chat\")\n\n# after\nkey = get_api_key(tenant_id, \"deepseek-chat@DeepSeek\")","handlingStrategy":"validation","validationCode":"_, _, provider = split_model_name(model_name)\nif not provider and not TenantModelService.get_by_id(model_name)[0]:\n    raise ValueError(\"Pass 'model@provider' or a tenant_model id\")","typeGuard":"def api_key_ref_valid(model_name: str) -> bool:\n    if TenantModelService.get_by_id(model_name)[0]:\n        return True\n    return bool(split_model_name(model_name)[2])","tryCatchPattern":"try:\n    key = get_api_key(tenant_id, model_name)\nexcept LookupError as e:\n    if str(e) == \"Provider name is required.\":\n        key = get_api_key(tenant_id, f\"{model_name}@{known_provider}\")","preventionTips":["Note this path has NO builtin-TEI exception — always suffix or use an id.","Keep one helper that formats model@provider strings for all config writes.","Reject bare names at config-save time with a clear message."],"tags":["model-name","api-key","provider-resolution","ragflow"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}