Skip to content

fix: speech store loadSettings uses raw fetchApi causing persistent error popup#1393

Closed
gdeyoung wants to merge 1 commit intoagent0ai:mainfrom
gdeyoung:fix/speech-store-settings-load-error
Closed

fix: speech store loadSettings uses raw fetchApi causing persistent error popup#1393
gdeyoung wants to merge 1 commit intoagent0ai:mainfrom
gdeyoung:fix/speech-store-settings-load-error

Conversation

@gdeyoung
Copy link
Copy Markdown
Contributor

Bug Summary

The speech store (webui/components/chat/speech/speech-store.js) shows a persistent "Failed to load speech settings" error popup when the app loads. This happens because loadSettings() uses the raw fetchApi() function to call /settings_get, which lacks proper CSRF token handling and response validation.

Root Cause

The speech store calls the settings API like this:

const response = await fetchApi("/settings_get", { method: "POST" });
const data = await response.json();

When the server returns a non-JSON response (e.g. an HTML redirect to /login during session initialization), response.json() throws a SyntaxError on the HTML content. This triggers the catch block which calls:

window.toastFetchError("Failed to load speech settings", error);

The result is a visible, confusing error popup that appears every time the app loads under certain conditions.

The Fix

The main settings store (webui/components/settings/settings-store.js) already handles this correctly using the proper API wrapper:

const response = await API.callJsonApi("settings_get", null);

The API.callJsonApi() wrapper (defined in webui/js/api.js) properly handles:

  • CSRF token injection
  • Response ok checking
  • Login redirect detection
  • Proper error messages

This PR aligns the speech store with the established pattern.

Changes

File: webui/components/chat/speech/speech-store.js

1. Add API module import

+import * as API from "/js/api.js";

2. Replace raw fetchApi with API.callJsonApi in loadSettings()

-      const response = await fetchApi("/settings_get", { method: "POST" });
-      const data = await response.json();
+      const data = await API.callJsonApi("settings_get", null);
       const settings = data?.settings || {};

3. Downgrade error handling (speech settings have sensible defaults)

-      window.toastFetchError("Failed to load speech settings", error);
-      console.error("Failed to load speech settings:", error);
+      console.warn("Failed to load speech settings, using defaults:", error);

Why This Is Safe

  • Matches existing pattern: The main settings store uses API.callJsonApi() for the same endpoint
  • No behavior change: Settings are loaded the same way, just with proper error handling
  • Graceful degradation: Speech settings have sensible defaults (tiny model, en language, etc.), so a load failure should not disrupt the user with a popup
  • Minimal diff: 3 insertions, 4 deletions — single file change

Testing

  • Verified the fix eliminates the error popup
  • Verified speech settings still load correctly after the fix
  • Verified the speech store falls back to defaults if the API call fails

Stats

 webui/components/chat/speech/speech-store.js | 7 ++++---
 1 file changed, 3 insertions(+), 4 deletions(-)

…ings load error

The speech store used raw fetchApi() to load settings which lacks proper CSRF
token handling and response validation. When the server returns a non-JSON
response (e.g. HTML redirect to /login), response.json() fails and shows a
persistent "Failed to load speech settings" error popup.

This aligns the speech store with the main settings store pattern which
already uses API.callJsonApi() with proper error handling.
@gdeyoung
Copy link
Copy Markdown
Contributor Author

gdeyoung commented Apr 6, 2026

Closing this PR to resubmit cleanly from a synced fork (v1.7). The fork was 578 commits behind upstream. Will resubmit with a fresh branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant