From c4a4e8b85e16dcf1cfebb054190e1ce060d2f883 Mon Sep 17 00:00:00 2001
From: psychedelicious <4822129+psychedelicious@users.noreply.github.com>
Date: Thu, 18 Sep 2025 19:53:27 +1000
Subject: [PATCH] feat(ui): toast warning when installed model is unidentified
---
invokeai/frontend/web/public/locales/en.json | 3 ++
.../src/features/system/store/constants.ts | 1 +
.../services/events/onModelInstallError.tsx | 8 ++++
.../src/services/events/setEventListeners.tsx | 41 +++++++++++++++++--
4 files changed, 50 insertions(+), 3 deletions(-)
diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json
index 17154cce87..785bc168d5 100644
--- a/invokeai/frontend/web/public/locales/en.json
+++ b/invokeai/frontend/web/public/locales/en.json
@@ -914,6 +914,9 @@
"hfTokenReset": "HF Token Reset",
"urlUnauthorizedErrorMessage": "You may need to configure an API token to access this model.",
"urlUnauthorizedErrorMessage2": "Learn how here.",
+ "unidentifiedModelTitle": "Unable to identify model",
+ "unidentifiedModelMessage": "We were unable to identify the type, base and/or format of the installed model. Try editing the model and selecting the appropriate settings for the model.",
+ "unidentifiedModelMessage2": "If you don't see the correct settings, or the model doesn't work after changing them, ask for help on or create an issue on .",
"imageEncoderModelId": "Image Encoder Model ID",
"installedModelsCount": "{{installed}} of {{total}} models installed.",
"includesNModels": "Includes {{n}} models and their dependencies.",
diff --git a/invokeai/frontend/web/src/features/system/store/constants.ts b/invokeai/frontend/web/src/features/system/store/constants.ts
index 68b363c509..0ca2d24129 100644
--- a/invokeai/frontend/web/src/features/system/store/constants.ts
+++ b/invokeai/frontend/web/src/features/system/store/constants.ts
@@ -1,3 +1,4 @@
export const githubLink = 'http://github.com/invoke-ai/InvokeAI';
+export const githubIssuesLink = 'https://github.com/invoke-ai/InvokeAI/issues';
export const discordLink = 'https://discord.gg/ZmtBAhwWhy';
export const websiteLink = 'https://www.invoke.com/';
diff --git a/invokeai/frontend/web/src/services/events/onModelInstallError.tsx b/invokeai/frontend/web/src/services/events/onModelInstallError.tsx
index 0cb77e294c..4b57381f19 100644
--- a/invokeai/frontend/web/src/services/events/onModelInstallError.tsx
+++ b/invokeai/frontend/web/src/services/events/onModelInstallError.tsx
@@ -4,6 +4,7 @@ import { logger } from 'app/logging/logger';
import type { AppDispatch, AppGetState } from 'app/store/store';
import { getPrefixedId } from 'features/controlLayers/konva/util';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
+import { discordLink, githubIssuesLink } from 'features/system/store/constants';
import { toast, toastApi } from 'features/toast/toast';
import { navigationApi } from 'features/ui/layouts/navigation-api';
import { t } from 'i18next';
@@ -191,3 +192,10 @@ const HFUnauthorizedToastDescription = () => {
);
};
+
+export const DiscordLink = () => {
+ return ;
+};
+export const GitHubIssuesLink = () => {
+ return ;
+};
diff --git a/invokeai/frontend/web/src/services/events/setEventListeners.tsx b/invokeai/frontend/web/src/services/events/setEventListeners.tsx
index 1db0e9b6f5..0cfa4cef26 100644
--- a/invokeai/frontend/web/src/services/events/setEventListeners.tsx
+++ b/invokeai/frontend/web/src/services/events/setEventListeners.tsx
@@ -1,4 +1,4 @@
-import { ExternalLink } from '@invoke-ai/ui-library';
+import { ExternalLink, Flex, Text } from '@invoke-ai/ui-library';
import { isAnyOf } from '@reduxjs/toolkit';
import { logger } from 'app/logging/logger';
import { socketConnected } from 'app/store/middleware/listenerMiddleware/listeners/socketConnected';
@@ -20,13 +20,14 @@ import ErrorToastDescription, { getTitle } from 'features/toast/ErrorToastDescri
import { toast } from 'features/toast/toast';
import { t } from 'i18next';
import { LRUCache } from 'lru-cache';
+import { Trans } from 'react-i18next';
import type { ApiTagDescription } from 'services/api';
import { api, LIST_ALL_TAG, LIST_TAG } from 'services/api';
import { modelsApi } from 'services/api/endpoints/models';
import { queueApi } from 'services/api/endpoints/queue';
import { workflowsApi } from 'services/api/endpoints/workflows';
import { buildOnInvocationComplete } from 'services/events/onInvocationComplete';
-import { buildOnModelInstallError } from 'services/events/onModelInstallError';
+import { buildOnModelInstallError, DiscordLink, GitHubIssuesLink } from 'services/events/onModelInstallError';
import type { ClientToServerEvents, ServerToClientEvents } from 'services/events/types';
import type { Socket } from 'socket.io-client';
import type { JsonObject } from 'type-fest';
@@ -292,7 +293,41 @@ export const setEventListeners = ({ socket, store, setIsConnected }: SetEventLis
socket.on('model_install_complete', (data) => {
log.debug({ data }, 'Model install complete');
- const { id } = data;
+ const { id, config } = data;
+
+ if (
+ config.type === 'unknown' ||
+ config.base === 'unknown' ||
+ /**
+ * Checking if type/base are 'unknown' technically narrows the config such that it's not possible for a config
+ * that passes to the `config.[type|base] === 'unknown'` checks. In the future, if we have more model config
+ * classes, this may change, so we will continue to check all three. Any one being 'unknown' is concerning
+ * enough to warrant a toast.
+ */
+ /* @ts-expect-error See note above */
+ config.format === 'unknown'
+ ) {
+ toast({
+ id: 'UNKNOWN_MODEL',
+ title: t('modelManager.unidentifiedModelTitle'),
+ description: (
+
+
+
+
+
+ , GitHubIssuesLink: }}
+ />
+
+
+ ),
+ status: 'error',
+ isClosable: true,
+ duration: null,
+ });
+ }
const installs = selectModelInstalls(getState()).data;