infiniflow/ragflow · error · LookupError

Provider id={model_obj.provider_id} not found for model {mod

Error message

Provider id={model_obj.provider_id} not found for model {model_name}.

What it means

LookupError raised by get_api_key during direct model-ID resolution: the tenant_model row exists, but TenantModelProviderService.get_by_id(model_obj.provider_id) failed, meaning the provider row backing this model is gone while the model row still references it. This is referential breakage inside the provider chain, not a caller input problem.

Source

Thrown at api/db/joint_services/tenant_model_service.py:444

        # req now has tenant_llm_id / tenant_embd_id etc. filled in
    """
    for name_field, (model_type, id_field) in _MODEL_NAME_TO_ID_FIELD_MAP.items():
        if name_field in params and id_field not in params:
            try:
                params[id_field] = resolve_model_id(tenant_id, model_type, params[name_field])
            except LookupError:
                logger.debug("Could not resolve %s → %s for tenant %s, skipping", name_field, id_field, tenant_id)
    return params


def get_api_key(tenant_id: str, model_name: str):
    # Try direct model ID (UUID) lookup first
    exist, model_obj = TenantModelService.get_by_id(model_name)
    if exist:
        # Verify tenant ownership through the provider chain
        ok, provider_obj = TenantModelProviderService.get_by_id(model_obj.provider_id)
        if not ok:
            raise LookupError(f"Provider id={model_obj.provider_id} not found for model {model_name}.")
        if tenant_id != provider_obj.tenant_id:
            joined_tenants = TenantService.get_joined_tenants_by_user_id(tenant_id)
            joined_tenant_ids = [t["tenant_id"] for t in joined_tenants]
            if provider_obj.tenant_id not in joined_tenant_ids:
                raise LookupError(f"Tenant {tenant_id} has no access to provider owned by tenant {provider_obj.tenant_id}.")

        exist_inst, instance_obj = TenantModelInstanceService.get_by_id(model_obj.instance_id)
        if not exist_inst:
            logger.warning(
                "Direct-ID resolution: instance not found | tenant_id=%s model_id=%s instance_id=%s",
                tenant_id,
                model_name,
                model_obj.instance_id,
            )
            raise LookupError(f"Instance {model_obj.instance_id} not found for model {model_name}.")
        logger.debug(
            "Direct-ID resolution: resolved | tenant_id=%s model_id=%s instance_id=%s",
            tenant_id,

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Delete the orphan tenant_model row (its provider is gone, so it is unusable) or re-add the provider to recreate rows.
  2. Re-select the model on any entity referencing the orphan id.
  3. If reproducible, fix the provider-deletion path to also remove dependent tenant_model rows (delete_models_by_instance_ids / cascade).
  4. Run a consistency check joining tenant_model to tenant_model_provider on provider_id to find other orphans.

Example fix

-- find orphan models
SELECT m.id, m.provider_id FROM tenant_model m
LEFT JOIN tenant_model_provider p ON p.id = m.provider_id
WHERE p.id IS NULL;
Defensive patterns

Strategy: try-catch

Validate before calling

exist, m = TenantModelService.get_by_id(model_id)
if exist:
    ok, _ = TenantModelProviderService.get_by_id(m.provider_id)
    if not ok:
        raise ValueError("Model references a deleted provider; re-register the model")

Type guard

def model_chain_intact(model_id: str) -> bool:
    exist, m = TenantModelService.get_by_id(model_id)
    if not exist:
        return False
    ok, _ = TenantModelProviderService.get_by_id(m.provider_id)
    return ok

Try / catch

try:
    key = get_api_key(tenant_id, model_id)
except LookupError as e:
    if "Provider id=" in str(e):
        # orphaned row: clean up and re-register, never retry as-is
        ...

Prevention

When it happens

Trigger: Calling get_api_key(tenant_id, model_id) where tenant_model.provider_id points at a deleted tenant_model_provider row — e.g. provider deletion removed provider/instance rows but left orphan tenant_model rows, or a partial/failed delete.

Common situations: Bugs or interrupted provider-deletion flows leaving orphans; direct DB edits; restores where related tables were inconsistent.

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/482724f6cb83f294. Report an issue: GitHub.