{"record":{"id":"1d5204c3f6130a22","repo":"DIYgod/RSSHub","slug":"unsupported-block-type-b-typename","errorCode":null,"errorMessage":"Unsupported block type: ${b.__typename}","messagePattern":"Unsupported block type: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":503,"severity":"warning","filePath":"lib/routes/theverge/index.ts","lineNumber":93,"sourceCode":"            return `<blockquote>${b.children.map((child) => renderBlock(child)).join('')}</blockquote>`;\n        case 'CoreSeparatorBlockType':\n            return '<hr>';\n        case 'HighlightBlockType':\n            return b.children.map((c) => renderBlock(c)).join('');\n        case 'ImageCompareBlockType':\n            return `<figure><img src=\"${b.leftImage.thumbnails.horizontal.url.split('?', 1)[0]}\" alt=\"${b.leftImage.alt}\" /><img src=\"${b.rightImage.thumbnails.horizontal.url.split('?', 1)[0]}\" alt=\"${b.rightImage.alt}\" /><figcaption>${b.caption.html}</figcaption></figure>`;\n        case 'ImageSliderBlockType':\n            return b.images.map((i) => `<figure><img src=\"${i.image.originalUrl.split('?', 1)[0]}\" alt=\"${i.alt}\" /><figcaption>${i.caption.html}</figcaption></figure>`).join('');\n        case 'MethodologyAccordionBlockType':\n            return `<h2>${b.heading.html}</h2>${b.sections.map((s) => `<h3>${s.heading.html}</h3>${s.content.html}`).join('')}`;\n        case 'ProductBlockType': {\n            const product = b.product;\n            return `<div><figure><img src=\"${product.image.thumbnails.horizontal.url.split('?', 1)[0]}\" alt=\"${product.image.alt}\" /><figcaption>${product.image.alt}</figcaption></figure><br><a href=\"${product.bestRetailLink.url}\">${product.title} $${product.bestRetailLink.price}</a><br>${product.description.html}${product.pros.html ? `<br>The Good${product.pros.html}The Bad${product.cons.html}` : ''}</div>`;\n        }\n        case 'TableBlockType':\n            return `<table><tr>${b.header.map((cell) => `<th>${cell}</th>`).join('')}</tr>${b.rows.map((row) => `<tr>${row.map((cell) => `<td>${cell}</td>`).join('')}</tr>`).join('')}</table>`;\n        default:\n            throw new Error(`Unsupported block type: ${b.__typename}`);\n    }\n};\n\nasync function handler(ctx) {\n    const link = ctx.req.param('hub') ? `https://www.theverge.com/rss/${ctx.req.param('hub')}/index.xml` : 'https://www.theverge.com/rss/index.xml';\n\n    const feed = await parser.parseURL(link);\n\n    const items = await Promise.all(\n        feed.items.map((item) =>\n            cache.tryGet(item.link!, async () => {\n                const response = await ofetch(item.link!);\n\n                const $ = load(response);\n\n                const nextData = JSON.parse($('script#__NEXT_DATA__').text());\n                const node = nextData.props.pageProps.hydration.responses.find((x) => x.operationName === 'PostLayoutQuery' || x.operationName === 'StreamLayoutQuery').data.node;\n","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/theverge/index.ts#L75-L111","documentation":"The Verge article renderer maps each content block by its __typename to an HTML fragment. The switch handles a fixed set (images, slider, methodology accordion, product, table, etc.); the default branch throws for any block __typename the renderer has not implemented. This surfaces when The Verge's CMS ships a new block type that appears in an article body.","triggerScenarios":"An article returned by the The Verge API contains a block whose __typename is not in the handled cases (e.g. a new 'NewsletterBlockType', 'VideoBlockType'). Rendering that article throws and the whole feed fetch can fail.","commonSituations":"The Verge adds a new CMS block; a one-off/embedded block type appears in a sponsored or feature article; the renderer was written against an older content schema.","solutions":["Change the default branch to return a safe placeholder (e.g. b.caption?.html or '') instead of throwing, so one unknown block does not break the article.","Identify the new __typename from the error, inspect its shape, and add a dedicated case.","Log unknown block types so new types are noticed without breaking feeds."],"exampleFix":"// before\ndefault:\n    throw new Error(`Unsupported block type: ${b.__typename}`);\n\n// after: degrade gracefully and surface the unknown type in logs\ndefault:\n    console.warn(`Unknown Verge block type: ${b.__typename}`);\n    return b.caption?.html ?? '';","handlingStrategy":"fallback","validationCode":"const SUPPORTED_BLOCKS = new Set(['ImageBlockType', 'ImagePairBlockType', 'ImageSliderBlockType', 'MethodologyAccordionBlockType', 'ProductBlockType', 'TableBlockType']);\nfunction isHandledBlock(typ: string): boolean {\n    return SUPPORTED_BLOCKS.has(typ);\n}\n// before rendering, skip/placeholder unknown blocks rather than throwing","typeGuard":"function isHandledBlockType(typ: string): boolean {\n    return ['ImageBlockType', 'ImagePairBlockType', 'ImageSliderBlockType', 'MethodologyAccordionBlockType', 'ProductBlockType', 'TableBlockType'].includes(typ);\n}","tryCatchPattern":"try {\n    return renderBlock(b);\n} catch (e) {\n    if (e instanceof Error && /Unsupported block type/.test(e.message)) {\n        // degrade: render caption or empty string, log the new type\n        console.warn(`Unknown Verge block: ${b.__typename}`);\n        return (b as { caption?: { html?: string } }).caption?.html ?? '';\n    }\n    throw e;\n}","preventionTips":["Make the renderer's default branch non-throwing (return '' or caption) so one new block does not break feeds.","Log unknown __typename values so new CMS blocks are noticed.","Periodically compare handled types against the blocks appearing in recent articles."],"tags":["api-contract","content","parsing","theverge"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}