infiniflow/ragflow · error · LookupError

TenantModel id={model_id} is disabled.

Error message

TenantModel id={model_id} is disabled.

What it means

LookupError raised by get_model_config_by_id when the tenant_model row exists but its status equals ActiveStatusEnum.INACTIVE. The row was found by id, then explicitly rejected because the user (or admin) disabled it. This is a state error, not a missing-row error: the model must be re-enabled before it can serve the requested model_type.

Source

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

            model_config["extra"] = model_extra

        if api_key_payload is not None:
            model_config["api_key_payload"] = api_key_payload

        return model_config
    else:
        raise LookupError(f"Model {model_name} not found for model {model_type_val}")


def get_model_config_by_id(tenant_id: str, model_type: str | enum.Enum, model_id: str):
    """Get model config from tenant_model by its id (CharField PK)."""
    model_type_val = model_type if isinstance(model_type, str) else model_type.value
    model_type_bin = calculate_model_type(model_type_val)
    exist, model_obj = TenantModelService.get_by_id(model_id)
    if not exist:
        raise LookupError(f"TenantModel id={model_id} not found.")
    if model_obj.status == ActiveStatusEnum.INACTIVE.value:
        raise LookupError(f"TenantModel id={model_id} is disabled.")
    if model_obj.status == ActiveStatusEnum.UNSUPPORTED.value:
        raise LookupError(f"TenantModel id={model_id} cannot be used as {model_type_val} model.")
    if not (model_obj.model_type & model_type_bin):
        raise LookupError(f"TenantModel id={model_id} cannot be used as {model_type_val} model.")

    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 id={model_id}.")

    # Validate that tenant_id owns the provider or is a joined tenant of the provider's owner.
    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}.")

    ok, instance_obj = TenantModelInstanceService.get_by_id(model_obj.instance_id)
    if not ok:

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Re-enable the model in System -> Model Providers (set status back to ACTIVE).
  2. If it should stay disabled, switch dependent datasets/assistants to another model id.
  3. Before disabling a model, audit references (tenant_embd_id / llm_id fields) and migrate them.
  4. In API integrations, catch LookupError and surface a 'model disabled, choose another' message instead of retrying.

Example fix

# before
config = get_model_config_by_id(tenant_id, LLMType.CHAT, llm_id)

# after
exist, obj = TenantModelService.get_by_id(llm_id)
if exist and obj.status == ActiveStatusEnum.INACTIVE.value:
    raise RuntimeError("Chat model is disabled; enable it in Model Providers or pick another")
config = get_model_config_by_id(tenant_id, LLMType.CHAT, llm_id)
Defensive patterns

Strategy: try-catch

Validate before calling

exist, obj = TenantModelService.get_by_id(model_id)
if exist and obj.status == ActiveStatusEnum.INACTIVE.value:
    raise RuntimeError("Model is disabled; enable it or choose another")

Type guard

def model_usable(model_id: str) -> bool:
    exist, obj = TenantModelService.get_by_id(model_id)
    return exist and obj.status != ActiveStatusEnum.INACTIVE.value

Try / catch

try:
    config = get_model_config_by_id(tenant_id, model_type, model_id)
except LookupError as e:
    if "is disabled" in str(e):
        # prompt user to enable the model or pick another; not transient
        ...

Prevention

When it happens

Trigger: Calling get_model_config_by_id with a model id whose tenant_model.status == ActiveStatusEnum.INACTIVE — typically after the user toggled the model off in Model Providers, or an admin bulk-disabled it, while a dataset/assistant still references it.

Common situations: Disabling an API-key-exhausted or deprecated model and forgetting dependent datasets; team spaces where one member disables a shared model; after provider key rotation the model is parked inactive.

Related errors


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