jackwener/OpenCLI · error · CommandExecutionError

Jike search API returned a malformed post

Error message

Jike search API returned a malformed post

What it means

mapPost validates each search result item from the Jike /1.0/search/integrate API before mapping it to an output row. It throws CommandExecutionError when an item is not an object or lacks a non-empty string id, because every row needs a stable id and post URL. This guards against Jike returning unexpected result shapes inside body.data.

Source

Thrown at clis/jike/search.js:25

const DEFAULT_LIMIT = 20;
const MAX_PAGES = 50;

async function fetchSearchPage(page, keyword, loadMoreKey) {
    const requestBody = {
        keywords: keyword,
        limit: PAGE_SIZE,
        ...(loadMoreKey ? { loadMoreKey } : {}),
    };
    const body = await postJikeApi(page, API_PATH, requestBody, 'Jike search API');
    if (!body || typeof body !== 'object' || body.success !== true || !Array.isArray(body.data)) {
        throw new CommandExecutionError(`Jike search API failed: ${String(body?.message || 'malformed response')}`);
    }
    return body;
}

function mapPost(post) {
    if (!post || typeof post !== 'object' || typeof post.id !== 'string' || !post.id) {
        throw new CommandExecutionError('Jike search API returned a malformed post');
    }
    const content = typeof post.content === 'string' ? post.content : '';
    return {
        id: post.id,
        author: typeof post.user?.screenName === 'string' ? post.user.screenName : '',
        content: content.replace(/\n/g, ' ').slice(0, 120),
        likes: Number.isFinite(Number(post.likeCount)) ? Number(post.likeCount) : 0,
        comments: Number.isFinite(Number(post.commentCount)) ? Number(post.commentCount) : 0,
        time: typeof post.actionTime === 'string' ? post.actionTime : (typeof post.createdAt === 'string' ? post.createdAt : ''),
        url: `https://web.okjike.com/originalPost/${post.id}`,
    };
}

async function searchPosts(page, keyword, limit) {
    const rows = [];
    const seenIds = new Set();
    const seenCursors = new Set();
    let loadMoreKey = null;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-login to Jike in the browser session (cookie strategy) and retry the search — stale sessions often yield degraded responses.
  2. Reduce --limit and retry to see if a specific post triggers it; if so the post's payload is anomalous.
  3. Update the CLI/package — the mapping may need adjusting for a Jike API schema change.
  4. Log the raw failing item (e.g. JSON.stringify) and file an issue so mapPost can be widened or the field fixed.

Example fix

// before
function mapPost(post) {
  if (!post || typeof post !== 'object' || typeof post.id !== 'string' || !post.id) {
    throw new CommandExecutionError('Jike search API returned a malformed post');
  }
  ...
}
// after: tolerate and skip bad items instead of failing the whole command
function mapPost(post) {
  if (!post || typeof post !== 'object' || typeof post.id !== 'string' || !post.id) {
    console.error('skipping malformed post:', JSON.stringify(post));
    return null;
  }
  ...
}
Defensive patterns

Strategy: type-guard

Validate before calling

// validate API items before mapping
function isMappedPost(item) {
  return item && typeof item === 'object' && typeof item.id === 'string' && item.id.length > 0;
}

Type guard

const isPost = (p) => !!p && typeof p === 'object' && typeof p.id === 'string' && !!p.id;

Try / catch

try {
  const rows = await runCli(['jike', 'search', keyword]);
} catch (e) {
  if (/malformed post/.test(e.message)) {
    console.error('Jike response schema changed; retry or update CLI');
    return [];
  }
  throw e;
}

Prevention

When it happens

Trigger: A data[] item in the search response is null, a non-object (e.g. a string), or an object whose post.id is missing, not a string, or an empty string. Items with type !== 'ORIGINAL_POST' are skipped before mapPost, so only ORIGINAL_POST entries reach this check.

Common situations: Jike changed its search response schema (field renamed from id); an A/B test returns a new result subtype that still reports type 'ORIGINAL_POST' but has no id; partial/corrupted API responses during rate limiting or login state degradation.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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