DIYgod/RSSHub · error

zhihu: JSDOM did not provide document.cookie accessors

Error message

zhihu: JSDOM did not provide document.cookie accessors

What it means

Thrown when the JSDOM environment constructed to execute Zhihu's challenge script does not expose `document.cookie` getter/setter accessors on `Document.prototype`. The generator needs to intercept `document.cookie` writes to capture the `__zse_ck` token the script sets, so if JSDOM's cookie descriptor is missing or non-functional, it closes the window and aborts.

Source

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

        runScripts: 'outside-only',
        pretendToBeVisual: true,
        virtualConsole: new VirtualConsole(),
    });
    const { window } = dom;
    Object.defineProperties(window.navigator, {
        userAgent: { value: ua, configurable: true },
        webdriver: { value: false, configurable: true },
    });
    window.TextEncoder = TextEncoder;
    window.TextDecoder = TextDecoder as typeof window.TextDecoder;
    window.atob = (value: string) => Buffer.from(value, 'base64').toString('binary');
    window.btoa = (value: string) => Buffer.from(value, 'binary').toString('base64');
    Object.assign(window, { __g: {} });

    const cookieDescriptor = Object.getOwnPropertyDescriptor(window.Document.prototype, 'cookie');
    if (!cookieDescriptor?.get || !cookieDescriptor.set) {
        window.close();
        throw new Error('zhihu: JSDOM did not provide document.cookie accessors');
    }
    const tokenPromise = new Promise<string>((resolve) => {
        Object.defineProperty(window.document, 'cookie', {
            configurable: true,
            get: cookieDescriptor.get,
            set(value: string) {
                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.

View on GitHub (pinned to bed535e087)

Solutions

  1. Pin or upgrade `jsdom` to a version known to expose a functional `document.cookie` accessor on `Document.prototype` (check the version currently working in RSSHub's lockfile).
  2. Ensure the JSDOM instance is constructed with a real `url` and `runScripts: 'outside-only'` so cookie APIs are initialized.
  3. If the new JSDOM defines `cookie` elsewhere (e.g. on `window.document` directly rather than the prototype), adjust the descriptor lookup target accordingly.

Example fix

// before
const cookieDescriptor = Object.getOwnPropertyDescriptor(window.Document.prototype, 'cookie');
if (!cookieDescriptor?.get || !cookieDescriptor.set) {
    window.close();
    throw new Error('zhihu: JSDOM did not provide document.cookie accessors');
}
// after — fall back to the instance if the prototype has no descriptor
const cookieDescriptor =
    Object.getOwnPropertyDescriptor(window.Document.prototype, 'cookie') ??
    Object.getOwnPropertyDescriptor(window.document, 'cookie');
if (!cookieDescriptor?.get || !cookieDescriptor.set) {
    window.close();
    throw new Error('zhihu: JSDOM did not provide document.cookie accessors');
}
Defensive patterns

Strategy: fallback

Validate before calling

// Verify JSDOM exposes cookie accessors before relying on the VM challenge
import { JSDOM } from 'jsdom';
function jsdomSupportsCookieAccessor() {
    const dom = new JSDOM('<!doctype html><html></html>', { url: 'https://example.com/' });
    const d = Object.getOwnPropertyDescriptor(dom.window.Document.prototype, 'cookie');
    dom.window.close();
    return !!(d?.get && d.set);
}

Try / catch

const cookieDescriptor = Object.getOwnPropertyDescriptor(window.Document.prototype, 'cookie')
    ?? Object.getOwnPropertyDescriptor(window.document, 'cookie');
if (!cookieDescriptor?.get || !cookieDescriptor.set) {
    window.close();
    // fall back to configured credentials instead of failing
    if (configuredDc0) return { dc0: configuredDc0 };
    throw new Error('zhihu: JSDOM did not provide document.cookie accessors');
}

Prevention

When it happens

Trigger: The installed `jsdom` version changed or removed its `document.cookie` property descriptor (different JSDOM major version, a stricter cookie config, or `Storage`/cookie access disabled), so `Object.getOwnPropertyDescriptor(window.Document.prototype, 'cookie')` returns undefined or an accessor-less descriptor.

Common situations: A dependency upgrade (jsdom) altered how `document.cookie` is defined; running under a runtime/Node version where JSDOM behaves differently; the `JSDOM` constructor options (e.g. `url`, `runScripts`) were changed in a way that disables cookie support.

Related errors


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