From 30df1433cc511c6c19f2cd60afef77996a40edad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=9E=E6=B3=95=E6=93=8D=E4=BD=9C?= Date: Mon, 20 Jul 2026 14:47:16 +0800 Subject: [PATCH] fix: can't create chat app when get tenant default model schema error (#39266) --- api/services/app_service.py | 36 +++++++++----- .../unit_tests/services/test_app_service.py | 47 +++++++++++++++++++ 2 files changed, 71 insertions(+), 12 deletions(-) diff --git a/api/services/app_service.py b/api/services/app_service.py index a6080879883..3c32d1984e2 100644 --- a/api/services/app_service.py +++ b/api/services/app_service.py @@ -408,6 +408,7 @@ class AppService: default_model_config = app_template.get("model_config") default_model_config = default_model_config.copy() if default_model_config else None if default_model_config and "model" in default_model_config: + default_model_dict = default_model_config["model"] # get model provider model_manager = ModelManager.for_tenant(tenant_id=account.current_tenant_id or "") @@ -422,7 +423,7 @@ class AppService: logger.exception("Get default model instance failed, tenant_id: %s", tenant_id) model_instance = None - if model_instance: + if model_instance is not None: if ( model_instance.model_name == default_model_config["model"]["name"] and model_instance.provider == default_model_config["model"]["provider"] @@ -430,17 +431,28 @@ class AppService: default_model_dict = default_model_config["model"] else: llm_model = cast(LargeLanguageModel, model_instance.model_type_instance) - model_schema = llm_model.get_model_schema(model_instance.model_name, model_instance.credentials) - if model_schema is None: - raise ValueError(f"model schema not found for model {model_instance.model_name}") - - default_model_dict = { - "provider": model_instance.provider, - "name": model_instance.model_name, - "mode": model_schema.model_properties.get(ModelPropertyKey.MODE), - "completion_params": {}, - } - else: + try: + model_schema = llm_model.get_model_schema(model_instance.model_name, model_instance.credentials) + if model_schema is None: + raise ValueError(f"model schema not found for model {model_instance.model_name}") + except Exception: + # A removed provider model must not prevent creating an app. + logger.warning( + "Default model schema is unavailable, tenant_id: %s, provider: %s, model: %s", + tenant_id, + model_instance.provider, + model_instance.model_name, + exc_info=True, + ) + model_instance = None + else: + default_model_dict = { + "provider": model_instance.provider, + "name": model_instance.model_name, + "mode": model_schema.model_properties.get(ModelPropertyKey.MODE), + "completion_params": {}, + } + if model_instance is None: try: provider, model = model_manager.get_default_provider_model_name( tenant_id=account.current_tenant_id or "", model_type=ModelType.LLM diff --git a/api/tests/unit_tests/services/test_app_service.py b/api/tests/unit_tests/services/test_app_service.py index 0fba9e82b32..9707855a6d7 100644 --- a/api/tests/unit_tests/services/test_app_service.py +++ b/api/tests/unit_tests/services/test_app_service.py @@ -8,6 +8,7 @@ from unittest.mock import MagicMock, patch import pytest from sqlalchemy.exc import IntegrityError +from graphon.model_runtime.entities.model_entities import ModelType from models import Account from models.model import App, AppMode, AppModelConfig from models.workflow import Workflow @@ -46,6 +47,52 @@ class TestCreateAppTransactionBoundary: assert phase_events == ["commit", "signal", "commit", "external"] + def test_falls_back_when_default_model_schema_is_unavailable(self) -> None: + session = MagicMock() + account = MagicMock(spec=Account, id="account-1", current_tenant_id="tenant-1") + model_type_instance = MagicMock() + model_type_instance.get_model_schema.side_effect = ValueError("Base model unknown-model not found") + model_instance = SimpleNamespace( + model_name="unknown-model", + provider="langgenius/openai/openai", + credentials={}, + model_type_instance=model_type_instance, + ) + model_manager = MagicMock() + model_manager.get_default_model_instance.return_value = model_instance + model_manager.get_default_provider_model_name.return_value = ("openai", "gpt-4o") + added_objects: list[object] = [] + session.add.side_effect = added_objects.append + + with ( + patch("services.app_service.ModelManager.for_tenant", return_value=model_manager), + patch("services.app_service.app_was_created.send"), + patch("services.app_service.enterprise_rbac_service.try_sync_creator_access_policy_member_bindings"), + patch( + "services.app_service.FeatureService.get_system_features", + return_value=SimpleNamespace(webapp_auth=SimpleNamespace(enabled=False)), + ), + patch("services.app_service.dify_config.BILLING_ENABLED", False), + ): + app = AppService().create_app( + "tenant-1", + CreateAppParams(name="Chat", mode=AppMode.CHAT.value), + account, + session=session, + ) + + app_model_config = next(obj for obj in added_objects if isinstance(obj, AppModelConfig)) + assert app.mode == AppMode.CHAT + assert app_model_config.model_dict == { + "provider": "openai", + "name": "gpt-4o", + "mode": "chat", + "completion_params": {}, + } + model_manager.get_default_provider_model_name.assert_called_once_with( + tenant_id="tenant-1", model_type=ModelType.LLM + ) + @pytest.mark.parametrize( "update_status",