DIYgod/RSSHub · error
Unknown type: ${contentItem.type}
Error message
Unknown type: ${contentItem.type} What it means
The mirror of error 664 but in the `xhu` (third-party Zhihu mirror API) activities route. The inner switch over a pin's content items handles `text`, `image`, `link`, `video` and `link_card`; any other `contentItem.type` reaches the `default` and throws, reporting the unknown type.
Source
Thrown at lib/routes/zhihu/xhu/activities.ts:115
break;
case 'link':
link = `<p><a href="${contentItem.url}" target="_blank">${contentItem.title}</a></p>`;
break;
case 'video':
link = `<p><video
controls="controls"
width="${contentItem.playlist[1].width}"
height="${contentItem.playlist[1].height}"
src="${contentItem.playlist[1].url}"></video></p>`;
break;
default:
throw new Error(`Unknown type: ${contentItem.type}`);
}
}
description = `${text}${link}${images.join('')}`;
url = `https://www.zhihu.com/pin/${detail.id}`;
break;
case 'question':
title = detail.title;
author = detail.author.name;
description = processImage(detail.detail);
url = `https://www.zhihu.com/question/${detail.id}`;
break;
case 'collection':
title = detail.title;
url = `https://www.zhihu.com/collection/${detail.id}`;
break;
case 'column':
title = detail.title;
description = `<p>${detail.intro}</p><p><img src="${detail.image_url}"/></p>`;View on GitHub (pinned to bed535e087)
Solutions
- Use the reported `contentItem.type` to add a matching `case` (link/image/iframe as appropriate to the payload fields).
- Make the `default` arm skip unknown items (`break` with no HTML) so one unsupported block cannot break the feed.
- Cross-reference the official `activities.ts` route to keep the two type lists in sync.
Example fix
// before
default:
throw new Error(`Unknown type: ${contentItem.type}`);
// after — degrade gracefully
default:
break; Defensive patterns
Strategy: type-guard
Validate before calling
const HANDLED = new Set(['text', 'image', 'link', 'video', 'link_card']);
function safePinContent(content) {
return Array.isArray(content) ? content.filter((c) => HANDLED.has(c.type)) : [];
} Type guard
type HandledPinType = 'text' | 'image' | 'link' | 'video' | 'link_card';
function isHandledPinType(item: { type: string }): item is { type: HandledPinType } {
return new Set<HandledPinType>(['text','image','link','video','link_card']).has(item.type as HandledPinType);
} Try / catch
for (const contentItem of detail.content) {
if (!isHandledPinType(contentItem)) continue;
// existing switch
} Prevention
- Filter pin content to known types before switching so unknown blocks are skipped.
- Keep this type set in sync with the official activities.ts route.
- Log new types at warn level to catch mirror/API additions.
When it happens
Trigger: The xhu mirror API returns a pin content block whose `type` is not in the handled set — because the mirror exposes a newer Zhihu content type, or the mirror normalizes types differently than the official endpoint.
Common situations: The xhu mirror is updated to pass through a new Zhihu pin block type; a reposted/nested pin carries a type the switch doesn't model; type-string casing or naming differs from the official route. The throw fails the whole activity feed.
Related errors
- Unknown type: ${contentItem.type}
- Unknown type: ${item.type}
- Unknown type: ${item.type}
- Unknown type: ${item.type}
- Unhandled thirdparty on ${link}: ${elem.attr('alias')}
AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12).
Data as JSON: /api/errors/44027f4dc5d7d448.
Report an issue: GitHub.