[GH-ISSUE #18277] issue: Mermaid code blocks containing syntax errors will cause the page to crash and become unusable #105545

Closed
opened 2026-05-18 03:35:22 -05:00 by GiteaMirror · 4 comments
Owner

Originally created by @ShirasawaSama on GitHub (Oct 13, 2025).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/18277

Check Existing Issues

  • I have searched for any existing and/or related issues.
  • I have searched for any existing and/or related discussions.
  • I am using the latest version of Open WebUI.

Installation Method

Git Clone

Open WebUI Version

0.6.33 & dev

Ollama Version (if applicable)

No response

Operating System

MacOS 26

Browser (if applicable)

No response

Confirmation

  • I have read and followed all instructions in README.md.
  • I am using the latest version of both Open WebUI and Ollama.
  • I have included the browser console logs.
  • I have included the Docker container logs.
  • I have provided every relevant configuration, setting, and environment variable used in my setup.
  • I have clearly listed every relevant configuration, custom setting, environment variable, and command-line option that influences my setup (such as Docker Compose overrides, .env values, browser settings, authentication configurations, etc).
  • I have documented step-by-step reproduction instructions that are precise, sequential, and leave nothing to interpretation. My steps:
  • Start with the initial platform/version/OS and dependencies used,
  • Specify exact install/launch/configure commands,
  • List URLs visited, user input (incl. example values/emails/passwords if needed),
  • Describe all options and toggles enabled or changed,
  • Include any files or environmental changes,
  • Identify the expected and actual result at each stage,
  • Ensure any reasonably skilled user can follow and hit the same issue.

Expected Behavior

The page has no rendering errors.

Actual Behavior

The entire page rendered incorrectly and became completely unusable.

Steps to Reproduce

  1. Using the deepseek-r1 model
  2. Ask the AI model "使用FX3U系列PLC开发电推杆控制程序。电推杆特性为:给24V电,电推杆伸出;断电,停在当前位置;反向给24V点,电推杆缩回。使用串口481与上位机通讯,上位机发4种不同的工作模式,控制电推杆的供电分别对应24V、0V、反接24V。" -> "继电器互锁应如何实现" -> "画出 硬件接线图+PLC梯形图互锁示例"
  3. Keep clicking the generated follow-up questions until a Mermaid chart appears on the page and a page rendering error occurs.

Logs & Screenshots

Image Image Image Image

Additional Information

No response

Originally created by @ShirasawaSama on GitHub (Oct 13, 2025). Original GitHub issue: https://github.com/open-webui/open-webui/issues/18277 ### Check Existing Issues - [x] I have searched for any existing and/or related issues. - [x] I have searched for any existing and/or related discussions. - [x] I am using the latest version of Open WebUI. ### Installation Method Git Clone ### Open WebUI Version 0.6.33 & dev ### Ollama Version (if applicable) _No response_ ### Operating System MacOS 26 ### Browser (if applicable) _No response_ ### Confirmation - [x] I have read and followed all instructions in `README.md`. - [x] I am using the latest version of **both** Open WebUI and Ollama. - [x] I have included the browser console logs. - [x] I have included the Docker container logs. - [x] I have **provided every relevant configuration, setting, and environment variable used in my setup.** - [x] I have clearly **listed every relevant configuration, custom setting, environment variable, and command-line option that influences my setup** (such as Docker Compose overrides, .env values, browser settings, authentication configurations, etc). - [x] I have documented **step-by-step reproduction instructions that are precise, sequential, and leave nothing to interpretation**. My steps: - Start with the initial platform/version/OS and dependencies used, - Specify exact install/launch/configure commands, - List URLs visited, user input (incl. example values/emails/passwords if needed), - Describe all options and toggles enabled or changed, - Include any files or environmental changes, - Identify the expected and actual result at each stage, - Ensure any reasonably skilled user can follow and hit the same issue. ### Expected Behavior The page has no rendering errors. ### Actual Behavior The entire page rendered incorrectly and became completely unusable. ### Steps to Reproduce 1. Using the deepseek-r1 model 2. Ask the AI model "使用FX3U系列PLC开发电推杆控制程序。电推杆特性为:给24V电,电推杆伸出;断电,停在当前位置;反向给24V点,电推杆缩回。使用串口481与上位机通讯,上位机发4种不同的工作模式,控制电推杆的供电分别对应24V、0V、反接24V。" -> "继电器互锁应如何实现" -> "画出 硬件接线图+PLC梯形图互锁示例" 3. Keep clicking the generated follow-up questions until a Mermaid chart appears on the page and a page rendering error occurs. ### Logs & Screenshots <img width="1544" height="1670" alt="Image" src="https://github.com/user-attachments/assets/026305f3-3cb5-43e9-aa8a-bcefeed91726" /> <img width="578" height="574" alt="Image" src="https://github.com/user-attachments/assets/7b6da4e4-f05a-4470-b4e6-70ced00486db" /> <img width="896" height="800" alt="Image" src="https://github.com/user-attachments/assets/cf7682fc-eda5-4d0c-ae5c-2540c0b102c4" /> <img width="1114" height="2088" alt="Image" src="https://github.com/user-attachments/assets/daf6408c-f9e9-40f3-9734-6c45cc63e7c1" /> ### Additional Information _No response_
GiteaMirror added the bug label 2026-05-18 03:35:22 -05:00
Author
Owner

@silentoplayz commented on GitHub (Oct 13, 2025):

Expected Behavior
The page has no rendering errors.

You're not going to get that with a model that can't generate a Mermaid code block successfully. I got many MermaidJS syntax related errors from models generating incorrect Mermaid code blocks, but not the particular issue that you've pointed out in this thread. It's too hit or miss.

<!-- gh-comment-id:3396452822 --> @silentoplayz commented on GitHub (Oct 13, 2025): > Expected Behavior > The page has no rendering errors. You're not going to get that with a model that can't generate a Mermaid code block successfully. I got many MermaidJS syntax related errors from models generating incorrect Mermaid code blocks, but not the particular issue that you've pointed out in this thread. It's too hit or miss.
Author
Owner

@rgaricano commented on GitHub (Oct 13, 2025):

The issue can be for an infinite loop of the reactive component, that block the execution on error.

  • Parse error is thrown from renderMermaidDiagram().
  • Caught in CodeBlock.svelte's try-catch.

But onUpdate(token) at the start of render() may be triggering parent component updates.
This causes the reactive statement $: if (_token) { render(); } to fire again CodeBlock.svelte creating an infinite error loop that freezes the browser.

Workaround:
Move onUpdate(token) to after the rendering attempt & add a guard to prevent re-rendering on the same token:

src/lib/components/chat/Messages/CodeBlock.svelte#L326-L350

const render = async () => {
    if (lastRenderedCode === code) return;
    lastRenderedCode = code;

    if (lang === 'mermaid' && (token?.raw ?? '').slice(-4).includes('```')) {
        try {
            mermaidHtml = await renderMermaidDiagram(code);
            onUpdate(token);
        } catch (error) {
            console.error('Failed to render mermaid diagram:', error);
            toast.error($i18n.t('Failed to render diagram') + `: ${error.message}`);
            mermaidHtml = null;
        }
    } else if ((lang === 'vega' || lang === 'vega-lite') && (token?.raw ?? '').slice(-4).includes('```')) {
        try {
            vegaHtml = await renderVegaVisualization(code);
            onUpdate(token);
        } catch (error) {
            console.error('Failed to render Vega visualization:', error);
            toast.error($i18n.t('Failed to render diagram') + `: ${error.message}`);
            vegaHtml = null;
        }
    }
};

	$: if (token) {
		if (JSON.stringify(token) !== JSON.stringify(_token)) {
			_token = token;
		}
	}

	$: if (_token) {
		render();
	}

	$: if (attributes) {
		onAttributesUpdate();
	}

I didn't try it!
If this fix it and is PRed: keep the vega part, it have the same situation (this fix is for both renderers) & please, add also error catching with re-throwing (to display it on toast) in the utility function layer for more control of both :

src/lib/utils/index.ts#L1596-L1622

export const renderMermaidDiagram = async (code: string) => {
	try {
		const { default: mermaid } = await import('mermaid');
		mermaid.initialize({
			startOnLoad: false,
			theme: document.documentElement.classList.contains('dark') ? 'dark' : 'default',
			securityLevel: 'loose'
		});
		const parseResult = await mermaid.parse(code, { suppressErrors: false });
		if (parseResult) {
			const { svg } = await mermaid.render(`mermaid-${uuidv4()}`, code);
			return svg;
		}
		return '';
	} catch (error) {
		console.error('Failed to render mermaid diagram:', error);
		throw error;
	}
};

export const renderVegaVisualization = async (spec: string) => {
	try {
		const vega = await import('vega');
		const parsedSpec = JSON.parse(spec);
		let vegaSpec = parsedSpec;
		if (parsedSpec.$schema && parsedSpec.$schema.includes('vega-lite')) {
			const vegaLite = await import('vega-lite');
			vegaSpec = vegaLite.compile(parsedSpec).spec;
		}
		const view = new vega.View(vega.parse(vegaSpec), { renderer: 'none' });
		const svg = await view.toSVG();
		return svg;
	} catch (error) {
		console.error('Failed to render Vega visualization:', error);
		throw error;
	}
};
<!-- gh-comment-id:3397275533 --> @rgaricano commented on GitHub (Oct 13, 2025): The issue can be for an infinite loop of the reactive component, that block the execution on error. - Parse error is thrown from renderMermaidDiagram(). - Caught in CodeBlock.svelte's try-catch. But `onUpdate(token)` at the start of `render()` may be triggering parent component updates. This causes the reactive statement `$: if (_token) { render(); }` to fire again CodeBlock.svelte creating an infinite error loop that freezes the browser. **Workaround:** Move `onUpdate(token)` to after the rendering attempt & add a guard to prevent re-rendering on the same token: src/lib/components/chat/Messages/CodeBlock.svelte#L326-L350 ``` const render = async () => { if (lastRenderedCode === code) return; lastRenderedCode = code; if (lang === 'mermaid' && (token?.raw ?? '').slice(-4).includes('```')) { try { mermaidHtml = await renderMermaidDiagram(code); onUpdate(token); } catch (error) { console.error('Failed to render mermaid diagram:', error); toast.error($i18n.t('Failed to render diagram') + `: ${error.message}`); mermaidHtml = null; } } else if ((lang === 'vega' || lang === 'vega-lite') && (token?.raw ?? '').slice(-4).includes('```')) { try { vegaHtml = await renderVegaVisualization(code); onUpdate(token); } catch (error) { console.error('Failed to render Vega visualization:', error); toast.error($i18n.t('Failed to render diagram') + `: ${error.message}`); vegaHtml = null; } } }; $: if (token) { if (JSON.stringify(token) !== JSON.stringify(_token)) { _token = token; } } $: if (_token) { render(); } $: if (attributes) { onAttributesUpdate(); } ``` I didn't try it! If this fix it and is PRed: keep the vega part, it have the same situation (this fix is for both renderers) & please, add also error catching with re-throwing (to display it on toast) in the utility function layer for more control of both : src/lib/utils/index.ts#L1596-L1622 ``` export const renderMermaidDiagram = async (code: string) => { try { const { default: mermaid } = await import('mermaid'); mermaid.initialize({ startOnLoad: false, theme: document.documentElement.classList.contains('dark') ? 'dark' : 'default', securityLevel: 'loose' }); const parseResult = await mermaid.parse(code, { suppressErrors: false }); if (parseResult) { const { svg } = await mermaid.render(`mermaid-${uuidv4()}`, code); return svg; } return ''; } catch (error) { console.error('Failed to render mermaid diagram:', error); throw error; } }; export const renderVegaVisualization = async (spec: string) => { try { const vega = await import('vega'); const parsedSpec = JSON.parse(spec); let vegaSpec = parsedSpec; if (parsedSpec.$schema && parsedSpec.$schema.includes('vega-lite')) { const vegaLite = await import('vega-lite'); vegaSpec = vegaLite.compile(parsedSpec).spec; } const view = new vega.View(vega.parse(vegaSpec), { renderer: 'none' }); const svg = await view.toSVG(); return svg; } catch (error) { console.error('Failed to render Vega visualization:', error); throw error; } }; ```
Author
Owner

@rgaricano commented on GitHub (Oct 13, 2025):

I edited the vega utility function, I had pasted it with an unused i18n parameter (remanent from first implementation)

<!-- gh-comment-id:3397517620 --> @rgaricano commented on GitHub (Oct 13, 2025): I edited the vega utility function, I had pasted it with an unused i18n parameter (remanent from first implementation)
Author
Owner

@tjbck commented on GitHub (Oct 14, 2025):

How do we reproduce this? Was this recently introduced with a refac?

<!-- gh-comment-id:3403947392 --> @tjbck commented on GitHub (Oct 14, 2025): How do we reproduce this? Was this recently introduced with a refac?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#105545