DIYgod/RSSHub · error
Unhandled mode on ${link}: ${value.mode}
Error message
Unhandled mode on ${link}: ${value.mode} What it means
Thrown by `card2Html` inside the `yuque` card case (a cross-document Yuque embed). It only handles `value.mode === 'card'` (renders a link) and `value.mode === 'embed'` (renders an iframe); any other mode value triggers this throw, reporting the document link and the unrecognized mode.
Source
Thrown at lib/routes/yuque/utils.ts:66
// YES, youku name with bilibli iframe
// https://www.yuque.com/api/docs/nn5lyk?book_id=297292&include_contributors=true
if (elem.attr('alias') === 'music163') {
html = `<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" height=66 src="${value.src}"></iframe>`;
} else if (elem.attr('alias') === 'bilibili' || elem.attr('alias') === undefined) {
html = `<iframe src="${value.src}&high_quality=1&autoplay=0" width="650" height="477" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe>`;
} else if (value.type === 'codepen') {
html = `<iframe height="265" style="width: 100%;" scrolling="no" title="codepen" src="${value.url}" frameborder="no" allowtransparency="true" allowfullscreen="true"></iframe>`;
} else {
throw new Error(`Unhandled thirdparty on ${link}: ${elem.attr('alias')}`);
}
break;
case 'yuque':
if (value.mode === 'card') {
html = `<a href='${value.src}'>${value.detail.title}</a>`;
} else if (value.mode === 'embed') {
html = `<iframe src="${value.url}" width="100%" height="518"></iframe>`;
} else {
throw new Error(`Unhandled mode on ${link}: ${value.mode}`);
}
break;
case 'video':
// fake video src
html = `<video src='${value.videoId}'></video>`;
break;
default:
throw new Error(`Unhandled card on ${link}: ${name}`);
}
elem.replaceWith(html);
};
export { card2Html };
View on GitHub (pinned to bed535e087)
Solutions
- Inspect the `value.mode` reported in the error and add a matching `else if` branch that renders the embed appropriately.
- If the new mode is link-like, reuse the `'card'` link template; if it is interactive, add an iframe template.
- Make the final `else` degrade gracefully (render a fallback link to `value.src`) instead of throwing so one embed cannot kill the document.
Example fix
// before
} else if (value.mode === 'embed') {
html = `<iframe src="${value.url}" width="100%" height="518"></iframe>`;
} else {
throw new Error(`Unhandled mode on ${link}: ${value.mode}`);
}
// after
} else if (value.mode === 'embed') {
html = `<iframe src="${value.url}" width="100%" height="518"></iframe>`;
} else {
html = `<a href='${value.src}'>${value.detail?.title ?? value.src}</a>`;
} Defensive patterns
Strategy: try-catch
Validate before calling
const knownYuqueModes = new Set(['card', 'embed']);
function isHandledYuqueMode(value) {
return knownYuqueModes.has(value.mode);
} Type guard
type YuqueCardValue = { mode?: string; src?: string; url?: string; detail?: { title?: string } };
function isHandledYuqueMode(value: YuqueCardValue): boolean {
return value.mode === 'card' || value.mode === 'embed';
} Try / catch
try {
card2Html(elem, link);
} catch (e) {
logger.warn(`Skipping unhandled yuque card mode on ${link}: ${(e as Error).message}`);
elem.replaceWith(`<a href='${link}'>[unsupported embed]</a>`);
} Prevention
- Catch card2Html failures per element so unknown modes render a fallback link instead of aborting.
- Track the set of modes you've seen in production logs to spot new ones Zhihu/Yuque ships.
- Default unknown modes to a link to value.src when available rather than throwing.
When it happens
Trigger: A Yuque document uses a `<card name="yuque">` embed whose `value.mode` is neither `'card'` nor `'embed'` — for instance Yuque adds a new preview/live-render mode, or the payload for an existing mode is restructured so the string no longer matches.
Common situations: Yuque introduces a new embed display mode; a mode string is renamed; the card payload's `mode` field is occasionally absent and coerced to a different value. The unhandled document then fails the entire feed.
Related errors
- Unhandled thirdparty on ${link}: ${elem.attr('alias')}
- Unhandled card on ${link}: ${name}
- Unknown type: ${contentItem.type}
- Unknown type: ${contentItem.type}
- Unknown type: ${item.type}
AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12).
Data as JSON: /api/errors/d6b6fe37f9feb162.
Report an issue: GitHub.