{"record":{"id":"cd750eda65979ad1","repo":"DIYgod/RSSHub","slug":"mihoyo-bbs-official-getpostcontent-failed-url","errorCode":null,"errorMessage":"mihoyo/bbs/official: getPostContent failed: ${url} - ${JSON.stringify(res)}","messagePattern":"mihoyo/bbs/official: getPostContent failed: (.+?) - (.+?)","errorType":"exception","errorClass":"MiHoYoOfficialError","httpStatus":null,"severity":"error","filePath":"lib/routes/mihoyo/bbs/official.ts","lineNumber":81,"sourceCode":"        url,\n    });\n    const list = response?.data?.data?.list;\n    return list;\n};\n\nconst getPostContent = async (row, default_gid = '2') => {\n    const post = row.post;\n    const post_id = post.post_id;\n    const query = new URLSearchParams({\n        post_id,\n    }).toString();\n    const url = `https://bbs-api.miyoushe.com/post/wapi/getPostFull?${query}`;\n    return await cache.tryGet(url, async () => {\n        const res = await got(url);\n        const fullRow = res?.data?.data?.post;\n        if (!fullRow) {\n            // throw an error to prevent an empty item from being cached and returned\n            throw new MiHoYoOfficialError(`mihoyo/bbs/official: getPostContent failed: ${url} - ${JSON.stringify(res)}`);\n        }\n        // default_gid should be useless since the above error-throwing line, but just in case\n        const gid = fullRow?.post?.game_id || default_gid;\n        const author = fullRow?.user?.nickname || '';\n        const content = fullRow?.post?.content || '';\n        const tags = fullRow?.topics?.map((item) => item.name) || [];\n        const description = renderOfficialDescription(post.has_cover, row.cover_list, content);\n        return {\n            // 文章标题\n            title: post.subject,\n            // 文章链接\n            link: `https://www.miyoushe.com/${GAME_SHORT_MAP[gid]}/article/${post_id}`,\n            // 文章正文\n            description,\n            // 文章发布日期\n            pubDate: parseDate(post.created_at * 1000),\n            // 文章标签\n            category: tags,","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/mihoyo/bbs/official.ts#L63-L99","documentation":"MiHoYoOfficialError thrown inside getPostContent when the getPostFull API returns a response whose data.data.post is missing. The route intentionally throws (rather than returning empty) to prevent cache.tryGet from caching an empty item — this preserves correctness so a transient failure can be retried rather than frozen.","triggerScenarios":"got(getPostFull?post_id=...) resolves, but res.data.data.post is falsy. The post_id is invalid, the post was deleted, the post is access-restricted, or Miyoushe returned an error envelope with HTTP 200. The full response is JSON-stringified into the message for diagnostics.","commonSituations":"A news-list item references a post that was later deleted; post is region/account restricted; transient upstream error; API envelope changed so the post field moved.","solutions":["Retry the feed after a short wait — transient for deleted/relisted posts.","If a specific post_id consistently fails, the post is gone; the news list will eventually drop it.","Inspect the JSON in the error message to see Miyoushe's actual response (message/retcode).","If retcode indicates auth, refresh MIHOYO_COOKIE."],"exampleFix":"// before — error includes: getPostContent failed: <url> - {\"retcode\":-100,...}\n\n// after (route-hardening option) — skip failed posts instead of failing the whole feed\nconst fullRow = res?.data?.data?.post;\nif (!fullRow) return null; // filter nulls out of items\n// then: items.filter(Boolean) before returning","handlingStrategy":"try-catch","validationCode":"// Optional: pre-check post_id format\nif (!/^[0-9]+$/.test(post_id)) return null; // skip malformed","typeGuard":"function hasPostFull(res: any): res is { data: { data: { post: object } } } {\n    return Boolean(res?.data?.data?.post);\n}","tryCatchPattern":"try {\n    const res = await got(url);\n    if (!res?.data?.data?.post) throw new MiHoYoOfficialError(`getPostContent failed: ${url}`);\n} catch (e) {\n    // skip this post rather than failing the whole feed","preventionTips":["Throw inside cache.tryGet so empty results aren't cached (current behavior — keep it).","Filter failed posts out of the final item list to keep the feed alive.","Log the retcode from the response for upstream-change diagnosis."],"tags":["mihoyo","upstream","data-integrity","caching"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}