jackwener/OpenCLI · error · EmptyResultError

Topic ${id} does not contain a readable main post body.

Error message

Topic ${id} does not contain a readable main post body.

What it means

The library renders the main post from its raw markdown; if raw is empty it falls back to converting the cooked HTML via htmlToMarkdown. If both yield an empty body, there is nothing readable to output, so an EmptyResultError is thrown.

Source

Thrown at clis/linux-do/topic-content.js:70

        frontMatter ? `---\n${frontMatter}\n---` : '',
        params.body.trim(),
    ].filter(Boolean).join('\n\n').trim();
}
function extractTopicContent(payload, id) {
    const topic = normalizeTopicPayload(payload);
    if (!topic) {
        throw new CommandExecutionError('linux.do returned an unexpected topic payload');
    }
    const posts = topic.post_stream?.posts ?? [];
    const mainPost = posts.find((post) => post.post_number === 1);
    if (!mainPost) {
        throw new EmptyResultError('linux-do/topic-content', `Could not find the main post for topic ${id}.`);
    }
    const body = typeof mainPost.raw === 'string' && mainPost.raw.trim()
        ? mainPost.raw.trim()
        : htmlToMarkdown(mainPost.cooked ?? '');
    if (!body) {
        throw new EmptyResultError('linux-do/topic-content', `Topic ${id} does not contain a readable main post body.`);
    }
    return {
        content: buildTopicMarkdownDocument({
            title: topic.title?.trim() ?? '',
            author: mainPost.username?.trim() ?? '',
            likes: typeof mainPost.like_count === 'number' ? mainPost.like_count : undefined,
            createdAt: toLocalTime(mainPost.created_at ?? ''),
            url: `${LINUX_DO_HOME}/t/${id}`,
            body,
        }),
    };
}
async function fetchTopicPayload(page, id) {
    const result = await page.evaluate(`(async () => {
    try {
      const res = await fetch('/t/${id}.json?include_raw=true', { credentials: 'include' });
      let data = null;
      try {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Sign in to linux.do in the browser session so full post bodies are served.
  2. Verify the post has visible content in the web UI.
  3. Check whether the post was hidden/deleted by moderators.
  4. Extend the pipeline to fall back to another field (e.g. cooked HTML as-is) if htmlToMarkdown output is empty.

Example fix

// before
const body = typeof mainPost.raw === 'string' && mainPost.raw.trim()
  ? mainPost.raw.trim()
  : htmlToMarkdown(mainPost.cooked ?? '');
// after
const body = (typeof mainPost.raw === 'string' && mainPost.raw.trim())
  ? mainPost.raw.trim()
  : htmlToMarkdown(mainPost.cooked ?? '') || (mainPost.cooked ?? '').trim();
Defensive patterns

Strategy: fallback

Validate before calling

const raw = mainPost?.raw?.trim();
const cooked = mainPost?.cooked?.trim();
if (!raw && !cooked) throw new Error(`Topic ${id} has no readable body`);

Type guard

const hasReadableBody = (post) =>
  Boolean((typeof post?.raw === 'string' && post.raw.trim()) || (typeof post?.cooked === 'string' && post.cooked.trim()));

Try / catch

try {
  return extractTopicContent(payload, id);
} catch (e) {
  if (e instanceof EmptyResultError && /readable main post body/.test(e.message)) {
    return { id, content: '' }; // degrade gracefully
  } else throw e;
}

Prevention

When it happens

Trigger: Main post exists but has both empty raw and empty cooked fields — e.g. post content removed/hidden, content behind login not captured by the browser scrape, or a post consisting only of removed embeds.

Common situations: Moderator-hidden or deleted-post bodies; linux.do returning posts with redacted content to anonymous/crawler sessions; posts whose body is only an image that failed to render into markdown.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/614f15ef93f389fb. Report an issue: GitHub.