{"record":{"id":"4d7f7cbf7439bddc","repo":"infiniflow/ragflow","slug":"provider-name-is-required-to-resolve-model-id-for","errorCode":null,"errorMessage":"Provider name is required to resolve model id for {model_name}.","messagePattern":"Provider name is required to resolve model id for (.+?)\\.","errorType":"exception","errorClass":"LookupError","httpStatus":null,"severity":"error","filePath":"api/db/joint_services/tenant_model_service.py","lineNumber":390,"sourceCode":"    return model_config\n\n\ndef resolve_model_id(tenant_id: str, model_type: str | enum.Enum, model_name: str) -> str | None:\n    \"\"\"Given a tenant_id, model_type and model_name (e.g. 'model@instance@provider'),\n    look up the corresponding tenant_model.id. Returns None if not found.\"\"\"\n    pure_model_name, instance_name, provider_name = split_model_name(model_name)\n    model_type_val = model_type if isinstance(model_type, str) else model_type.value\n\n    # Builtin TEI embedding — no tenant_model row exists\n    compose_profiles = os.getenv(\"COMPOSE_PROFILES\", \"\")\n    is_tei_builtin_embedding = (\n        model_type_val == LLMType.EMBEDDING.value and \"tei-\" in compose_profiles and pure_model_name == os.getenv(\"TEI_MODEL\", \"\") and (provider_name == \"Builtin\" or not provider_name)\n    )\n    if is_tei_builtin_embedding:\n        return None\n\n    if not provider_name:\n        raise LookupError(f\"Provider name is required to resolve model id for {model_name}.\")\n\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 for model {model_name}.\")\n\n    instance_obj = _resolve_instance_for_model(provider_obj, instance_name, model_name)\n    model_obj = TenantModelService.get_by_provider_id_and_instance_id_and_model_type_and_model_name(provider_obj.id, instance_obj.id, model_type_val, pure_model_name)\n    if not model_obj:\n        raise LookupError(f\"Model {model_name} not found for type {model_type_val}.\")\n    return model_obj.id\n\n\n# Mapping from model-name field → (LLMType, tenant_model id field)\n_MODEL_NAME_TO_ID_FIELD_MAP: dict[str, tuple[str, str]] = {\n    \"llm_id\": (LLMType.CHAT, \"tenant_llm_id\"),\n    \"embd_id\": (LLMType.EMBEDDING, \"tenant_embd_id\"),\n    \"rerank_id\": (LLMType.RERANK, \"tenant_rerank_id\"),\n    \"asr_id\": (LLMType.ASR, \"tenant_asr_id\"),","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/api/db/joint_services/tenant_model_service.py#L372-L408","documentation":"LookupError raised in the model-name-to-id resolver (split_model_name path) when the 'model[@instance]@provider' string carries no provider segment. Except for the builtin TEI embedding escape hatch (COMPOSE_PROFILES contains 'tei-', name equals TEI_MODEL, provider 'Builtin' or empty), a provider name is mandatory to locate the tenant_model_provider row and then the model row. The error means the name string was a bare model name with no '@provider' suffix.","triggerScenarios":"Calling the resolver (e.g. via get_model_id_from_name used by id-param backfill) with names like 'gpt-4o' instead of 'gpt-4o@OpenAI'; an empty/null provider segment after split_model_name; TEI builtin conditions not all met (e.g. TEI_MODEL env unset) so the escape hatch is skipped.","commonSituations":"Hand-written DSL or API payloads storing bare model names; configs migrated from an older scheme where the provider suffix was optional; TEI deployment where COMPOSE_PROFILES or TEI_MODEL drifted so the builtin branch no longer matches.","solutions":["Format the model reference as model@provider (or model@instance@provider), e.g. 'gpt-4o@OpenAI'.","For builtin TEI embedding, verify COMPOSE_PROFILES includes the tei- profile and TEI_MODEL matches the name, or just use the 'Builtin' provider suffix.","Normalize stored model names on write so the provider suffix is always present.","Check split_model_name output for your string to see which segment is empty."],"exampleFix":"# before\nmodel_id = get_model_id_from_name(tenant_id, LLMType.CHAT, \"deepseek-chat\")\n\n# after\nmodel_id = get_model_id_from_name(tenant_id, LLMType.CHAT, \"deepseek-chat@DeepSeek\")","handlingStrategy":"validation","validationCode":"_, _, provider = split_model_name(model_name)\nif not provider:\n    raise ValueError(f\"'{model_name}' lacks a provider: use 'model@Provider'\")","typeGuard":"def has_provider_suffix(model_name: str) -> bool:\n    return bool(split_model_name(model_name)[2])","tryCatchPattern":"try:\n    model_id = get_model_id_from_name(tenant_id, model_type, model_name)\nexcept LookupError as e:\n    if \"Provider name is required\" in str(e):\n        model_name = f\"{model_name}@{default_provider}\"\n        model_id = get_model_id_from_name(tenant_id, model_type, model_name)","preventionTips":["Always store model references as 'model[@instance]@provider'.","For TEI builtin embedding, keep COMPOSE_PROFILES and TEI_MODEL consistent with stored names.","Centralize model-string formatting in one helper instead of string concatenation at call sites."],"tags":["model-name","provider-resolution","ragflow","configuration"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}