jackwener/OpenCLI · warning · EmptyResultError

zhihu user

Error message

zhihu user

What it means

EmptyResultError with resource 'zhihu user' is thrown when the in-page fetch returns HTTP 404 — i.e. no Zhihu user exists for the given slug. It is the 'not found' branch of the user profile command's error handling.

Source

Thrown at clis/zhihu/user.js:40

        const apiUrl = `https://www.zhihu.com/api/v4/members/${encodeURIComponent(slug)}?include=${encodeURIComponent(INCLUDE)}`;
        const data = unwrapEvaluateResult(await page.evaluate(`
      (async () => {
        try {
          const r = await fetch(${JSON.stringify(apiUrl)}, { credentials: 'include' });
          if (!r.ok) return { __httpError: r.status };
          return await r.json();
        } catch (err) {
          return { __fetchError: err?.message || String(err) };
        }
      })()
    `));
        if (!data || typeof data !== 'object' || Array.isArray(data) || data.__httpError || data.__fetchError) {
            const status = data?.__httpError;
            if (status === 401 || status === 403) {
                throw new AuthRequiredError('www.zhihu.com', 'Failed to fetch Zhihu user profile');
            }
            if (status === 404) {
                throw new EmptyResultError('zhihu user', `No Zhihu user was found for ${slug}.`);
            }
            throw new CommandExecutionError(status ? `Zhihu user request failed (HTTP ${status})` : 'Zhihu user request failed', data?.__fetchError ? String(data.__fetchError) : 'Try again later or rerun with -v');
        }
        if (!data.url_token || !data.id || !data.name) {
            throw new CommandExecutionError('Zhihu user response missing identity fields', 'Zhihu may have changed its API shape');
        }
        return [{
            url_token: String(data.url_token || ''),
            name: String(data.name || ''),
            headline: String(data.headline || ''),
            followers: data.follower_count ?? 0,
            following: data.following_count ?? 0,
            answers: data.answer_count ?? 0,
            articles: data.articles_count ?? 0,
            voteup: data.voteup_count ?? 0,
            url: data.url_token ? `https://www.zhihu.com/people/${data.url_token}` : '',
        }];
    },

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the url_token in the browser by visiting https://www.zhihu.com/people/<slug>
  2. Re-resolve the user's current url_token (it can change after renames)
  3. Check for typos or truncation in the slug argument
  4. Confirm the account still exists and wasn't deactivated

Example fix

// before
node cli.js zhihu user wen-jie-1647
// after
node cli.js zhihu user wen-jie-16-47
Defensive patterns

Strategy: validation

Validate before calling

// before calling, sanity-check the slug format and existence in the browser
const slugOk = typeof slug === 'string' && /^[A-Za-z0-9_-]+$/.test(slug);
if (!slugOk) throw new Error('Invalid url_token format: ' + slug);
// existence check: fetch https://www.zhihu.com/people/<slug> and expect 200

Type guard

const isPlausibleSlug = (s) => typeof s === 'string' && s.length > 0 && /^[A-Za-z0-9_-]+$/.test(s);

Try / catch

try {
  const user = await fetchZhihuUser(slug);
} catch (e) {
  if (e instanceof EmptyResultError) {
    console.warn(`No Zhihu user for ${slug}; skipping`);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Requesting a profile whose url_token does not exist: a typo in the slug, a user who renamed their url_token, a deactivated/deleted account, or passing a display name instead of the url_token that happens to 404.

Common situations: Hardcoded slugs that broke after the user renamed their profile; scraping historical usernames; copying an incomplete URL fragment as the slug.

Related errors


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