jackwener/OpenCLI · error · CommandExecutionError

Jike search API failed: ${String(body?.message || 'malformed

Error message

Jike search API failed: ${String(body?.message || 'malformed response')}

What it means

fetchSearchPage posts to the Jike search API and requires a body that is an object with success === true and a `data` array. Any other response is wrapped in CommandExecutionError, including the server-provided message when present.

Source

Thrown at clis/jike/search.js:18

import { ArgumentError, CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';
import { cli, Strategy } from '@jackwener/opencli/registry';
import { normalizeJikeLimit, postJikeApi, requireJikeIdentity } from './utils.js';

const API_PATH = '/1.0/search/integrate';
const PAGE_SIZE = 20;
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}`,
    };

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-authenticate / refresh the Jike session token
  2. Read the embedded message in the error to distinguish rate limit vs auth vs server error
  3. Retry with backoff after a rate limit
  4. Simplify/escape the search keyword and verify it returns results in the Jike app
Defensive patterns

Strategy: try-catch

Validate before calling

// basic pre-flight checks before searching
if (!process.env.JIKE_TOKEN) throw new Error('JIKE_TOKEN not set');
if (!keyword || !keyword.trim()) throw new Error('keyword required');

Type guard

function isSearchBody(b) {
  return b !== null && typeof b === 'object' && b.success === true && Array.isArray(b.data);
}

Try / catch

try {
  await cli('jike', 'search', [keyword]).run();
} catch (e) {
  if (String(e.message).startsWith('Jike search API failed:')) {
    await sleep(3000); // search rate limits are strict; backoff then retry
  } else throw e;
}

Prevention

When it happens

Trigger: The Jike search endpoint returns success !== true, a missing/non-array data field, an HTML error page, or a rate-limit/auth-failure payload instead of the expected envelope.

Common situations: Jike search rate limiting (search endpoints are often stricter); expired session token; special characters in the keyword breaking the request; Jike API outage; envelope change in a new API version.

Understand the failure class

Related errors


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