{"record":{"id":"f6e3d00523d32872","repo":"DIYgod/RSSHub","slug":"unknown-asset-type-content-assettype-in-item","errorCode":null,"errorMessage":"Unknown asset type: ${content.assetType} in ${item.link}","messagePattern":"Unknown asset type: (.+?) in (.+?)","errorType":"exception","errorClass":"Error","httpStatus":503,"severity":"error","filePath":"lib/routes/afr/utils.ts","lineNumber":25,"sourceCode":"    const $ = load(response);\n\n    const reduxState = JSON.parse($('script#__REDUX_STATE__').text().replaceAll(':undefined', ':null').match('__REDUX_STATE__=(.*);')?.[1] || '{}');\n\n    const content = reduxState.page.content;\n    const asset = content.asset;\n\n    switch (content.assetType) {\n        case 'liveArticle':\n            item.description = asset.posts.map((post) => `<h2>${post.asset.headlines.headline}</h2>${post.asset.body}`).join('');\n            break;\n\n        case 'article':\n        case 'featureArticle':\n            item.description = renderArticle(asset, item.link);\n            break;\n\n        default:\n            throw new Error(`Unknown asset type: ${content.assetType} in ${item.link}`);\n    }\n\n    return item;\n};\n\nconst renderArticle = (asset, link: string) => {\n    const $ = load(asset.body, null, false);\n    $('x-placeholder').each((_, el) => {\n        const $el = $(el);\n        const id = $el.attr('id');\n        if (!id) {\n            $el.replaceWith('');\n        }\n\n        const placeholder = asset.bodyPlaceholders[id!];\n        switch (placeholder?.type) {\n            case 'callout':\n            case 'relatedStory':","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/afr/utils.ts#L7-L43","documentation":"The AFR (Financial Review) renderer switches on content.assetType and handles liveArticle, article, and featureArticle. Any other assetType hits the default branch and throws a generic `Error` reporting the offending type and the item link, so unexpected content surfaces loudly rather than silently rendering an empty description.","triggerScenarios":"AFR's live-article API returns an item whose content.assetType is something new (e.g. 'video', 'gallery', 'podcast', 'newsletter') not covered by the switch.","commonSituations":"Upstream schema/pilot change introducing a new content type; a feed entry that points at a previously-unseen article format.","solutions":["Report the assetType value and item link to the route maintainers so a new case can be added.","Short-term, filter the offending item out of the list before calling the renderer.","Pin to a feed/query that returns only known asset types."],"exampleFix":"// before\nswitch (content.assetType) {\n    case 'liveArticle': ...\n    case 'article':\n    case 'featureArticle': ...\n    default: throw new Error(`Unknown asset type: ${content.assetType} in ${item.link}`);\n}\n// after — degrade gracefully instead of failing the whole feed\n    default:\n        item.description = asset?.body ?? '';\n        item.title = item.title ?? 'Unsupported asset type ' + content.assetType;\n","handlingStrategy":"type-guard","validationCode":"const KNOWN_ASSET_TYPES = new Set(['liveArticle','article','featureArticle']);\nfunction knownAfrAsset(t) {\n  return KNOWN_ASSET_TYPES.has(t);\n}","typeGuard":"function isKnownAfrAssetType(t): t is 'liveArticle'|'article'|'featureArticle' {\n  return t === 'liveArticle' || t === 'article' || t === 'featureArticle';\n}","tryCatchPattern":"try {\n  return renderAfrItem(content, item);\n} catch (e) {\n  if (e instanceof Error && /Unknown asset type/.test(e.message)) {\n    // degrade: keep the item with whatever body is available, instead of failing the feed\n    item.description = content?.asset?.body ?? '';\n    return item;\n  }\n  throw e;\n}","preventionTips":["Treat a new assetType as an upstream schema change — log it and report to maintainers.","Filter items to known assetTypes before rendering if feed completeness is optional.","Don't catch and silently drop; surface the type so the route can be extended."],"tags":["upstream-dependent","schema","rsshub","error-class-mismatch"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}