openclaw - ✅(Solved) Fix [Bug]: The string returned by the model may cause markedjs to freeze. [2 pull requests, 5 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#49021Fetched 2026-04-08 00:49:37
View on GitHub
Comments
5
Participants
3
Timeline
10
Reactions
0
Author
Timeline (top)
commented ×5cross-referenced ×2labeled ×2referenced ×1

the model return the string [\n {\n "docid": "4015981857",\n "title": "磁盘压测",\n "content": "# 一、创建专用压测目录\\n新建tests磁盘压测专用目录(隔离测试环境)\\n创建固定大小的测试文件(安全边界)\\n验证文件属性\\n# 二、磁盘压测\\n```shell\\nfio --name=root --filename=/data/tests/testfile --rw=randread --size=10G --bs=64k --ioengine=libaio --iodepth=8 --direct=1 --numjobs=1 --runtime=300 --time_based --group_reporting --eta=always\\n```\\n输入完整压测命令\\n```shell\\n--name=root\\n```\\n测试名称\\n```shell\\n--filename=/data/tests/testfile\\n```\\n专用测试文件\\n```shell\\n--rw=randread #read/write/randread/randwrite/randrw\\n```\\n模式 #顺序读/顺序写/随机读/随机写/混合模式\\n```shell\\n-size=10G\\n```\\n使用整个文件\\n```shell\\n--bs=64k\\n```\\n块大小\\n```shell\\n--ioengine=libaio\\n```\\n异步IO引擎\\n```shell\\n--iodepth=8\\n```\\nIO队列深度\\n```shell\\n-direct=1\\n```\\n直写磁盘\\n```shell\\n--numjobs=1\\n```\\n并发任务数\\n```shell\\n--runtime=300\\n```\\n运行时间\\n```shell\\n--time_based\\n```\\n保证运行时间\\n```shell\\n-group_reporting\\n```\\n汇总报告\\n```shell\\n--output=/data/fio_ and It may cause stuttering in Markdown rendering.

import { marked } from "marked";
const a = '[\n  {\n    "docid": "4015981857",\n    "title": "磁盘压测",\n    "content": "# 一、创建专用压测目录\\n新建tests磁盘压测专用目录(隔离测试环境)\\n创建固定大小的测试文件(安全边界)\\n验证文件属性\\n# 二、磁盘压测\\n```shell\\nfio --name=root --filename=/data/tests/testfile --rw=randread --size=10G --bs=64k --ioengine=libaio --iodepth=8 --direct=1 --numjobs=1 --runtime=300 --time_based --group_reporting --eta=always\\n```\\n输入完整压测命令\\n```shell\\n--name=root\\n```\\n测试名称\\n```shell\\n--filename=/data/tests/testfile\\n```\\n专用测试文件\\n```shell\\n--rw=randread #read/write/randread/randwrite/randrw\\n```\\n模式                            #顺序读/顺序写/随机读/随机写/混合模式\\n```shell\\n-size=10G\\n```\\n使用整个文件\\n```shell\\n--bs=64k\\n```\\n块大小\\n```shell\\n--ioengine=libaio\\n```\\n异步IO引擎\\n```shell\\n--iodepth=8\\n```\\nIO队列深度\\n```shell\\n-direct=1\\n```\\n直写磁盘\\n```shell\\n--numjobs=1\\n```\\n并发任务数\\n```shell\\n--runtime=300\\n```\\n运行时间\\n```shell\\n--time_based\\n```\\n保证运行时间\\n```shell\\n-group_reporting\\n```\\n汇总报告\\n```shell\\n--output=/data/fio_'
console.log(a);

const rendered = marked.parse(`${a}`, {
    // gfm: true,
    // breaks: true,
})
console.log(rendered);

I think it was caused by markedjs https://github.com/markedjs/marked/issues/3917

Root Cause

const rendered = marked.parse(${a}, { // gfm: true, // breaks: true, }) console.log(rendered);

I think it was caused by markedjs
https://github.com/markedjs/marked/issues/3917

Fix Action

Fixed

PR fix notes

PR #49034: fix(webchat): guard against marked.parse freeze on many unclosed code fences

Description (problem / solution / changelog)

Summary

  • Problem: marked.parse() enters exponential backtracking and freezes the browser tab when model output contains many unclosed fenced code blocks (e.g. escaped JSON with embedded shell snippets)
  • Why it matters: browser tab becomes unresponsive, user must force-close
  • What changed: added a pre-parse guard in ui/src/ui/markdown.ts that counts fenced code block markers; when there are >40 unclosed fences (odd count), falls back to plain text rendering
  • What did NOT change: normal markdown rendering, code block display, existing size guards

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #49021

User-visible / Behavior Changes

When model output has many unclosed code fences (>40 odd-count), the webchat renders it as escaped plain text instead of freezing.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: any (browser)
  • Runtime/container: webchat UI
  • Model/provider: any model that returns escaped JSON with many code fences

Steps

  1. Model returns a string with 40+ backtick-fenced code blocks, many unclosed
  2. Webchat calls toSanitizedMarkdownHtml() to render the response
  3. marked.parse() enters exponential backtracking

Expected

  • Response renders without freezing

Actual

  • Browser tab freezes indefinitely

Evidence

  • Failing test/log before + passing after — added test_adapt_with_grain_dataset regression test

Human Verification (required)

  • Verified scenarios: reproduced the freeze pattern from #49021 with the test case; confirmed guard triggers and falls back to plain text
  • Edge cases checked: normal markdown with <40 fences still renders via marked; even-count fences (properly closed) still render via marked
  • What you did not verify: real browser rendering (no browser env available)

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: revert the fence-count guard in ui/src/ui/markdown.ts
  • Files/config to restore: ui/src/ui/markdown.ts
  • Known bad symptoms reviewers should watch for: legitimate markdown with many code blocks rendering as plain text instead of formatted

Risks and Mitigations

  • Risk: legitimate content with >40 unclosed code fences rendered as plain text
    • Mitigation: threshold is high (40+ fences AND odd count); real model output rarely has this many unclosed fences

Changed files

  • ui/src/ui/markdown.test.ts (modified, +11/-0)
  • ui/src/ui/markdown.ts (modified, +13/-0)

PR #49137: fix(ui): bypass marked on escaped fence storms

Description (problem / solution / changelog)

Fixes #49021

Summary

  • bypass marked.parse for repeated escaped fenced-code dumps embedded in JSON-like text
  • fall back to the existing plain-text markdown renderer for these high-risk inputs
  • add a regression test that ensures the risky path never calls marked.parse

Changed files

  • ui/src/ui/markdown.test.ts (modified, +28/-0)
  • ui/src/ui/markdown.ts (modified, +22/-0)

Code Example

import { marked } from "marked";
const a = '[\n  {\n    "docid": "4015981857",\n    "title": "磁盘压测",\n    "content": "# 一、创建专用压测目录\\n新建tests磁盘压测专用目录(隔离测试环境)\\n创建固定大小的测试文件(安全边界)\\n验证文件属性\\n# 二、磁盘压测\\n

---

I think it was caused by markedjs
https://github.com/markedjs/marked/issues/3917

### Steps to reproduce

1. create a session
2. replace the string to the session.content
3. 

### Expected behavior

render the markdown successfully

### Actual behavior

The browser will freeze.

### OpenClaw version

2026.3.17

### Operating system

macos

### Install method

_No response_

### Model

anymodel

### Provider / routing chain

anyprovider

### Config file / key location

_No response_

### Additional provider/model setup details

_No response_

### Logs, screenshots, and evidence
RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Summary

the model return the string [\n {\n "docid": "4015981857",\n "title": "磁盘压测",\n "content": "# 一、创建专用压测目录\\n新建tests磁盘压测专用目录(隔离测试环境)\\n创建固定大小的测试文件(安全边界)\\n验证文件属性\\n# 二、磁盘压测\\n```shell\\nfio --name=root --filename=/data/tests/testfile --rw=randread --size=10G --bs=64k --ioengine=libaio --iodepth=8 --direct=1 --numjobs=1 --runtime=300 --time_based --group_reporting --eta=always\\n```\\n输入完整压测命令\\n```shell\\n--name=root\\n```\\n测试名称\\n```shell\\n--filename=/data/tests/testfile\\n```\\n专用测试文件\\n```shell\\n--rw=randread #read/write/randread/randwrite/randrw\\n```\\n模式 #顺序读/顺序写/随机读/随机写/混合模式\\n```shell\\n-size=10G\\n```\\n使用整个文件\\n```shell\\n--bs=64k\\n```\\n块大小\\n```shell\\n--ioengine=libaio\\n```\\n异步IO引擎\\n```shell\\n--iodepth=8\\n```\\nIO队列深度\\n```shell\\n-direct=1\\n```\\n直写磁盘\\n```shell\\n--numjobs=1\\n```\\n并发任务数\\n```shell\\n--runtime=300\\n```\\n运行时间\\n```shell\\n--time_based\\n```\\n保证运行时间\\n```shell\\n-group_reporting\\n```\\n汇总报告\\n```shell\\n--output=/data/fio_ and It may cause stuttering in Markdown rendering.

import { marked } from "marked";
const a = '[\n  {\n    "docid": "4015981857",\n    "title": "磁盘压测",\n    "content": "# 一、创建专用压测目录\\n新建tests磁盘压测专用目录(隔离测试环境)\\n创建固定大小的测试文件(安全边界)\\n验证文件属性\\n# 二、磁盘压测\\n```shell\\nfio --name=root --filename=/data/tests/testfile --rw=randread --size=10G --bs=64k --ioengine=libaio --iodepth=8 --direct=1 --numjobs=1 --runtime=300 --time_based --group_reporting --eta=always\\n```\\n输入完整压测命令\\n```shell\\n--name=root\\n```\\n测试名称\\n```shell\\n--filename=/data/tests/testfile\\n```\\n专用测试文件\\n```shell\\n--rw=randread #read/write/randread/randwrite/randrw\\n```\\n模式                            #顺序读/顺序写/随机读/随机写/混合模式\\n```shell\\n-size=10G\\n```\\n使用整个文件\\n```shell\\n--bs=64k\\n```\\n块大小\\n```shell\\n--ioengine=libaio\\n```\\n异步IO引擎\\n```shell\\n--iodepth=8\\n```\\nIO队列深度\\n```shell\\n-direct=1\\n```\\n直写磁盘\\n```shell\\n--numjobs=1\\n```\\n并发任务数\\n```shell\\n--runtime=300\\n```\\n运行时间\\n```shell\\n--time_based\\n```\\n保证运行时间\\n```shell\\n-group_reporting\\n```\\n汇总报告\\n```shell\\n--output=/data/fio_'
console.log(a);

const rendered = marked.parse(`${a}`, {
    // gfm: true,
    // breaks: true,
})
console.log(rendered);

I think it was caused by markedjs https://github.com/markedjs/marked/issues/3917

Steps to reproduce

  1. create a session
  2. replace the string to the session.content

Expected behavior

render the markdown successfully

Actual behavior

The browser will freeze.

OpenClaw version

2026.3.17

Operating system

macos

Install method

No response

Model

anymodel

Provider / routing chain

anyprovider

Config file / key location

No response

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Impact and severity

No response

Additional information

No response

extent analysis

Fix Plan

To resolve the issue with Markdown rendering causing the browser to freeze, we need to address the problem with the marked library. The issue seems to be related to the large input string that contains a mix of Markdown and other characters, which is causing the rendering to fail.

Here are the steps to fix the issue:

  • Update the marked library: Ensure you are using the latest version of the marked library, as updates may have addressed similar issues.
  • Sanitize the input: Before passing the string to marked.parse(), sanitize the input to remove any unnecessary characters or escape sequences that might be causing the issue.
  • Use a timeout: Implement a timeout when rendering the Markdown to prevent the browser from freezing. You can use a library like dompurify to sanitize the HTML output.

Example code:

import { marked } from "marked";
import DOMPurify from "dompurify";

const input = '[\n  {\n    "docid": "4015981857",\n    "title": "磁盘压测",\n    "content": "..."}';

// Sanitize the input
const sanitizedInput = DOMPurify.sanitize(input);

// Render the Markdown with a timeout
const timeout = 10000; // 10 seconds
const rendered = marked.parse(sanitizedInput, {
  // Options
});

// Use the rendered output
console.log(rendered);

Verification

To verify that the fix worked, test the rendering of the Markdown content with the updated code. The browser should no longer freeze, and the Markdown should be rendered correctly.

Extra Tips

  • Always sanitize user-input data to prevent security vulnerabilities and rendering issues.
  • Use a library like dompurify to sanitize HTML output and prevent XSS attacks.
  • Consider using a more efficient Markdown rendering library, such as remark or markdown-it, which may handle large inputs better.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

render the markdown successfully

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING