moeru-ai/airi · warning
Failed to process markdown with syntax highlighting, using f
Error message
Failed to process markdown with syntax highlighting, using fallback:
What it means
The async markdown upgrade path (await process(content) followed by DOMPurify.sanitize) threw — most often inside the syntax-highlighting pipeline. The synchronous processSync render was already applied by processContent, and the catch leaves processedContent at that sync result, which is the 'fallback' the message refers to. Stale writes are prevented by the requestId === processRequestId check, so the un-highlighted render simply stays.
Source
Thrown at packages/stage-ui/src/components/markdown/markdown-renderer.vue:26
interface Props {
content: string
class?: string | string[]
}
const props = defineProps<Props>()
const processedContent = ref('')
const { process, processSync } = useMarkdown()
let processRequestId = 0
async function processRichContent(content: string, requestId: number) {
try {
const result = DOMPurify.sanitize(await process(content))
if (requestId === processRequestId)
processedContent.value = result
}
catch (error) {
console.warn('Failed to process markdown with syntax highlighting, using fallback:', error)
}
}
function processContent() {
const content = props.content
const requestId = ++processRequestId
if (!content) {
processedContent.value = ''
return
}
try {
processedContent.value = DOMPurify.sanitize(processSync(content))
}
catch (error) {
console.warn('Failed to process markdown:', error)
processedContent.value = ''View on GitHub (pinned to 677329427f)
Solutions
- Inspect the logged error: unknown language ids and bundle load failures are the usual causes
- Normalize or strip language ids on code fences before processing
- Bundle the highlighter locally instead of dynamic imports that can fail offline
- Keep the sync fallback explicit: on catch, assign DOMPurify.sanitize(processSync(content)) guarded by the requestId check
Example fix
// before
catch (error) {
console.warn('Failed to process markdown with syntax highlighting, using fallback:', error)
}
// after: make the promised fallback explicit (sync render stays, highlighted one retries next watch)
catch (error) {
console.warn('Failed to process markdown with syntax highlighting, using fallback:', error)
if (requestId === processRequestId)
processedContent.value = DOMPurify.sanitize(processSync(content))
} Defensive patterns
Strategy: fallback
Try / catch
try {
const result = DOMPurify.sanitize(await process(content))
if (requestId === processRequestId) processedContent.value = result
}
catch (error) {
console.warn('Failed to process markdown with syntax highlighting, using fallback:', error)
// sync render (processSync) already filled processedContent; it stays as the fallback
} Prevention
- Bundle the highlighter locally instead of dynamic CDN imports so HMR/offline cannot break it
- Normalize code-fence language ids before highlighting
- Keep the requestId check on every write so stale renders cannot win the race
- Make the fallback explicit in the catch by re-assigning the sanitized sync result
When it happens
Trigger: Code fence with an unknown or misspelled language id; the highlighter bundle failing to load (offline dynamic import, HMR teardown); very large inputs failing in the async path.
Common situations: Chat messages containing code blocks with exotic languages; dev-server offline for the highlighter bundle; very long pasted documents.
Related errors
- Failed to process markdown:
- [Whisper Worker] fp16 encoder failed, falling back to fp32:
- [context-bridge] spark:notify handling failed; using fallbac
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/61296e6f13116faf.
Report an issue: GitHub.