CloakHQ/CloakBrowser · warning

[cloakbrowser] CLOAKBROWSER_WIDEVINE_CDM is set but has no m

Error message

[cloakbrowser] CLOAKBROWSER_WIDEVINE_CDM is set but has no manifest.json; skipping Widevine hint seeding

What it means

The environment variable CLOAKBROWSER_WIDEVINE_CDM points to a directory that does not contain a manifest.json, so the library cannot identify a valid Widevine CDM and skips seeding the Widevine hint into the profile. This is a best-effort warning: the launch proceeds, but DRM-protected media (e.g. Netflix, Spotify web) will not use your custom CDM.

Source

Thrown at js/src/widevine.ts:100

 * Write the Widevine CDM hint file into a persistent profile before launch.
 * `binaryPath` is the resolved chrome executable; the CDM is looked for next to
 * it. No-op on non-Linux, when disabled via CLOAKBROWSER_WIDEVINE, or when no
 * sideloaded CDM is present. Never throws — a failure must not break launch.
 */
export function seedWidevineHint(userDataDir: string, binaryPath: string): void {
  if (process.platform !== "linux") return;
  if (seedingDisabled()) return;
  // Empty userDataDir = Playwright's ephemeral profile (its own temp dir);
  // a persistent hint can't be placed there, and "" would pollute the CWD.
  if (!userDataDir) return;

  // Everything below is best-effort and must never break the browser launch,
  // so the whole body (resolution + write) is guarded.
  try {
    const cdmDir = resolveWidevineCdmDir(binaryPath);
    if (cdmDir === null) {
      if (process.env.CLOAKBROWSER_WIDEVINE_CDM !== undefined) {
        console.warn(
          "[cloakbrowser] CLOAKBROWSER_WIDEVINE_CDM is set but has no manifest.json; " +
            "skipping Widevine hint seeding",
        );
      }
      return;
    }

    const hintDir = path.join(userDataDir, "WidevineCdm");
    fs.mkdirSync(hintDir, { recursive: true });
    const hintFile = path.join(hintDir, HINT_FILENAME);
    // cdmDir is already absolute/resolved.
    const content = JSON.stringify({ Path: cdmDir });

    try {
      if (isFile(hintFile) && fs.readFileSync(hintFile, "utf-8") === content) {
        return; // already seeded correctly
      }
    } catch {

View on GitHub (pinned to d6bad5de26)

Solutions

  1. Verify the directory actually contains manifest.json alongside the CDM library: ls $CLOAKBROWSER_WIDEVINE_CDM.
  2. Point CLOAKBROWSER_WIDEVINE_CDM at the exact versioned CDM folder that contains manifest.json.
  3. Re-download/re-extract the Widevine CDM if the extraction was partial.
  4. If you don't need DRM, unset the variable to silence the warning.

Example fix

# before
export CLOAKBROWSER_WIDEVINE_CDM=/opt/widevine   # contains only libwidevinecdm.so

# after
export CLOAKBROWSER_WIDEVINE_CDM=/opt/widevine/4.10.2559.0  # contains manifest.json + libwidevinecdm.so
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs';
import path from 'node:path';
const cdm = process.env.CLOAKBROWSER_WIDEVINE_CDM;
if (cdm && !fs.existsSync(path.join(cdm, 'manifest.json'))) {
  throw new Error(`CLOAKBROWSER_WIDEVINE_CDM has no manifest.json: ${cdm}`);
}

Type guard

const isCdmDirWithManifest = (dir: string): boolean =>
  fs.existsSync(path.join(dir, 'manifest.json'));

Prevention

When it happens

Trigger: Setting CLOAKBROWSER_WIDEVINE_CDM=/path/to/dir where the dir lacks manifest.json (only e.g. libwidevinecdm.so, or wrong path), then calling launchPersistentContext, which calls seedWidevineHint.

Common situations: Pointing at the wrong directory level (the folder above the versioned CDM folder), incomplete CDM extraction, or a path to a file rather than the CDM directory. Also happens when the built-in resolution found nothing and the env var was the user's attempted override.

Related errors


AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28). Data as JSON: /api/errors/905c2fa824ea941d. Report an issue: GitHub.