DIYgod/RSSHub · error

zhihu: WASM VM did not produce a __zse_ck

Error message

zhihu: WASM VM did not produce a __zse_ck

What it means

Thrown when the challenge script, executed inside the JSDOM VM context, fails to set a valid `__zse_ck` cookie token within the 3-second race timeout. The generator runs Zhihu's obfuscated WASM-backed script and watches the intercepted `document.cookie` writes for a token containing `-`; if none arrives before `wait(3000)` resolves, `zseCk` stays undefined and this error fires.

Source

Thrown at lib/routes/zhihu/utils.ts:182

                Reflect.apply(cookieDescriptor.set!, window.document, [value]);
                const token = value.match(/__zse_ck=([^;]+)/)?.[1];
                if (token?.includes('-')) {
                    resolve(token);
                }
            },
        });
    });

    let zseCk: string | undefined;
    try {
        // Zhihu's challenge is intentionally delivered as executable JavaScript.
        new Script(vmScript).runInContext(dom.getInternalVMContext());
        zseCk = (await Promise.race([tokenPromise, wait(3000)])) as string | undefined;
    } finally {
        window.close();
    }
    if (!zseCk) {
        throw new Error('zhihu: WASM VM did not produce a __zse_ck');
    }
    return { dc0, zseCk, ua };
};

const getGeneratedZseCredentials = (url: string, apiPath: string, configuredDc0: string) => {
    const cacheKey = `zhihu:zse-ck:v4:${configuredDc0 ? md5(configuredDc0) : 'guest'}`;
    const pending = pendingZseCredentials.get(cacheKey);
    if (pending) {
        return pending;
    }

    const created = (async () => {
        try {
            return await cache.tryGet(cacheKey, () => generateZseCk(url, apiPath, configuredDc0), config.cache.contentExpire, false);
        } finally {
            pendingZseCredentials.delete(cacheKey);
        }
    })();

View on GitHub (pinned to bed535e087)

Solutions

  1. Supply `config.zhihu.cookies` with a freshly captured `d_c0` (and `__zse_ck` if your flow caches it) to reduce reliance on the in-VM generator.
  2. Inspect whether the token format changed — if Zhihu stopped embedding `-`, relax the `token?.includes('-')` guard and the regex accordingly after verifying.
  3. Increase the `wait(3000)` budget only if profiling shows the script legitimately needs more time on your hardware; a structural failure will not be fixed by a longer timeout.
  4. Confirm required globals (`TextEncoder`, `TextDecoder`, `atob`, `btoa`, `__g`) are injected before `runInContext`.

Example fix

// before
zseCk = (await Promise.race([tokenPromise, wait(3000)])) as string | undefined;
// after — longer budget plus a debug hook to see what cookie was set
zseCk = (await Promise.race([tokenPromise, wait(8000)])) as string | undefined;
if (!zseCk) {
    console.debug('zhihu zse-ck challenge produced cookie:', lastSeenCookie);
}
Defensive patterns

Strategy: retry

Try / catch

// Retry the in-VM challenge with backoff; surface what cookie was seen on failure
let zseCk;
for (let i = 0; i < 2; i++) {
    try {
        zseCk = await runChallengeOnce(vmScript, dom);
        if (zseCk) break;
    } catch (e) { /* last attempt rethrows below */ }
}
if (!zseCk) throw new Error('zhihu: WASM VM did not produce a __zse_ck');

Prevention

When it happens

Trigger: Zhihu's challenge script changed its algorithm/output so the cookie it sets no longer matches the `__zse_ck=([^;]+)` pattern or no longer contains `-`; the WASM module failed to load/run in the JSDOM sandbox; or computation simply exceeded the 3 s budget under load.

Common situations: Zhihu updates the `__zse_ck` generation logic (new version, different token format); the VM lacks a needed global (`TextEncoder`/`atob`/`__g`) so the script errors silently; a CPU-constrained host makes 3 s too tight; a JSDOM/Node version incompatibility breaks `runInContext`.

Related errors


AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12). Data as JSON: /api/errors/7464fb55b9d21ba7. Report an issue: GitHub.