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

  1. Inspect the `value.mode` reported in the error and add a matching `else if` branch that renders the embed appropriately.
  2. If the new mode is link-like, reuse the `'card'` link template; if it is interactive, add an iframe template.
  3. 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

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


AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12). Data as JSON: /api/errors/d6b6fe37f9feb162. Report an issue: GitHub.