{"record":{"id":"8b5d7e62962b12dd","repo":"jackwener/OpenCLI","slug":"linux-do-returned-an-unexpected-topic-payload","errorCode":null,"errorMessage":"linux.do returned an unexpected topic payload","messagePattern":"linux\\.do returned an unexpected topic payload","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linux-do/topic-content.js","lineNumber":59,"sourceCode":"        if (typeof value === 'number') {\n            frontMatterLines.push(`${key}: ${value}`);\n        }\n        else {\n            // Quote strings that could be misinterpreted by YAML parsers\n            const needsQuote = /[#{}[\\],&*?|>!%@`'\"]/.test(value) || /: /.test(value) || /:$/.test(value) || value.includes('\\n');\n            frontMatterLines.push(`${key}: ${needsQuote ? `'${value.replace(/'/g, \"''\")}'` : value}`);\n        }\n    }\n    const frontMatter = frontMatterLines.join('\\n');\n    return [\n        frontMatter ? `---\\n${frontMatter}\\n---` : '',\n        params.body.trim(),\n    ].filter(Boolean).join('\\n\\n').trim();\n}\nfunction extractTopicContent(payload, id) {\n    const topic = normalizeTopicPayload(payload);\n    if (!topic) {\n        throw new CommandExecutionError('linux.do returned an unexpected topic payload');\n    }\n    const posts = topic.post_stream?.posts ?? [];\n    const mainPost = posts.find((post) => post.post_number === 1);\n    if (!mainPost) {\n        throw new EmptyResultError('linux-do/topic-content', `Could not find the main post for topic ${id}.`);\n    }\n    const body = typeof mainPost.raw === 'string' && mainPost.raw.trim()\n        ? mainPost.raw.trim()\n        : htmlToMarkdown(mainPost.cooked ?? '');\n    if (!body) {\n        throw new EmptyResultError('linux-do/topic-content', `Topic ${id} does not contain a readable main post body.`);\n    }\n    return {\n        content: buildTopicMarkdownDocument({\n            title: topic.title?.trim() ?? '',\n            author: mainPost.username?.trim() ?? '',\n            likes: typeof mainPost.like_count === 'number' ? mainPost.like_count : undefined,\n            createdAt: toLocalTime(mainPost.created_at ?? ''),","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linux-do/topic-content.js#L41-L77","documentation":"extractTopicContent calls normalizeTopicPayload on the fetched topic JSON; if the payload cannot be normalized into a recognizable topic object (null/undefined result), it throws a CommandExecutionError. This guards against feeding malformed or non-topic data into the extraction pipeline.","triggerScenarios":"fetchTopicPayload returns a body that, after normalization, is not a topic object — e.g. the JSON endpoint returns an HTML login page, an error object, a deleted/hidden topic response, or null data.","commonSituations":"Expired or missing browser session so linux.do returns a login/error page; deleted or restricted topic; scraping/captcha interstitial; linux.do API schema change.","solutions":["Ensure you are signed in to linux.do in the controlling browser session (`browser sign-in` flow).","Verify the topic ID exists and is publicly viewable.","Log the raw payload returned by fetchTopicPayload to inspect what linux.do actually sent.","Retry later — the site may be serving an interstitial or outage."],"exampleFix":"// before\nconst payload = await fetchTopicPayload(page, 12345);\nconst content = extractTopicContent(payload, 12345);\n// after\nconst payload = await fetchTopicPayload(page, 12345);\nif (!payload?.id) {\n  throw new Error('Topic payload unusable — check linux.do session in browser');\n}\nconst content = extractTopicContent(payload, 12345);","handlingStrategy":"type-guard","validationCode":"if (!payload || typeof payload !== 'object' || !payload.id) {\n  throw new Error('Topic payload is not a valid topic object');\n}","typeGuard":"const isTopicPayload = (p) =>\n  Boolean(p && typeof p === 'object' && typeof p.id === 'number' && Array.isArray(p.post_stream?.posts));","tryCatchPattern":"try {\n  return extractTopicContent(payload, id);\n} catch (e) {\n  if (e instanceof CommandExecutionError && /unexpected topic payload/.test(e.message)) {\n    console.error('linux.do did not return topic JSON — check your browser session.');\n  } else throw e;\n}","preventionTips":["Keep a signed-in linux.do browser session","Verify topics exist before batch processing","Log raw payloads when parsing fails"],"tags":["http","payload-parsing","discourse","session"],"backgroundTag":"unexpected-response-payload","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}