Skip to main content
Errors come from three places:
  • The browser refuses a switch by printing apostate: <reason> on stderr and exiting with status 1. The packages report that as a failed launch.
  • The Python package raises a subclass of ApostateError. Python API lists the classes.
  • The Node package throws a subclass of ApostateError with a code string. Node API lists the classes and codes.
From 0.4.4 neither package puts a proxy credential into a message. In 0.4.3 a failed launch can echo the --apostate-profile value, which holds the credential base64-encoded. Troubleshooting starts from symptoms instead of messages.

Error classes

Switches and seeds

A value above the host

Cause. A per-field switch asked for more cores or memory than the host has. Fix. Pass a value at or below the host’s, or leave the switch out and let the seed choose. A seed’s own draw is lowered to the host’s automatically.

Host mode with a persona or override

The Python and Node packages refuse the same combination before launch with host inheritance disables every layer below it, so a platform persona cannot be applied at the same time (Node code APOSTATE_HOST_INHERITANCE_PERSONA). Cause. --fingerprint=host (or off, false, 0, disable, disabled) together with --fingerprint-platform, --fingerprint-anchor or a per-field switch. Fix. Drop one of them.

A GPU string from another family

Cause. --fingerprint-gpu-renderer or --fingerprint-gpu-vendor names a model that is not in the GPU family this launch drew. Fix. Use a string from the list in the message, or add --fingerprint-anchor with the family that has the model. GPU models lists every family’s strings.

A screen that cannot hold the window

Cause. --fingerprint-screen-width or --fingerprint-screen-height is smaller than --window-size, or too small for the taskbar or menu bar. Fix. Pass a larger screen or a smaller window.

A seed the browser cannot use

The packages refuse such a seed earlier: Python with fingerprint string must match [A-Za-z0-9][A-Za-z0-9._:-]* or fingerprint must be at most 512 bytes; the binary rejects a longer seed, Node with fingerprint must be a non-negative safe integer or a stable non-empty string. Cause. The seed is empty, over 512 bytes, or contains a space or a character outside ASCII. Fix. Use letters, digits, ., _, : and -, starting with a letter or digit, such as shop-account-1.

An unknown or misspelt switch

Python raises ConfigurationError. Node throws ProfileResolutionError with code APOSTATE_MISSPELLED_FINGERPRINT_SWITCH or APOSTATE_UNKNOWN_FINGERPRINT_SWITCH. Cause. A switch in args starts with --fingerprint but is not one the browser reads, or is within two edits of one. The browser would ignore it without a word. Fix. Use the spelling from Switches.

Noise turned off with a value

Cause. --fingerprint-noise with false, 0, no, off, disable or disabled. Fix. Leave the switch out. Noise is off by default.

An unknown GPU family or platform

These are logged, not refused. The launch goes ahead.
Cause. A family id or platform name the browser does not know. With an unknown family the launch presents the host’s own values on every surface. With an unknown platform it presents the host’s default persona. Fix. Use an id from GPU models and windows, macos or linux.

Launch options

A persistent profile passed to launch()

Node throws a message that names launchPersistentContext(userDataDir, options), with code APOSTATE_USER_DATA_DIR_ON_LAUNCH, or APOSTATE_USER_DATA_DIR_SWITCH_IN_ARGS for --user-data-dir in args. Cause. user_data_dir or userDataDir passed to launch(), or --user-data-dir in args. Fix. Call launch_persistent_context(path, ...) or launchPersistentContext(path, options).

A timezone that is not an IANA zone

From 0.4.4 both packages refuse the name before launch. Python raises ConfigurationError, and Node throws RangeError:
Cause. timezone names a zone that the host’s tz database (Python) or Intl (Node) does not know, such as a typo or an abbreviation like CEST. In 0.4.3 the name went into TZ, and a page’s Intl.DateTimeFormat().resolvedOptions().timeZone read undefined. Fix. Pass an IANA name, such as Europe/Berlin or America/New_York.

A proxy switch in args (Node)

Code APOSTATE_PROXY_SWITCH_IN_ARGS. Fix. Pass the proxy URL as the proxy option.

Options passed to new_page()

Node throws a TypeError with the same text in Node’s names, newPage() and newContext(options). Cause. Page options such as viewport given to the browser’s new_page(). Fix. Pass them to launch(), which gives them to the profile’s context, or open an off-the-record context with new_context(...).

A profile and a seed together

Node code APOSTATE_ENVELOPE_SEED_CONFLICT. Cause. A profile that describes a device, and --fingerprint in args. Fix. Use one or the other. A profile you write replaces composition.

A profile that does not match the schema

Node reports the first problem, such as profile.cpu.cores is not part of the schema. Cause. An unknown key, a wrong type or a value out of range. Fix. Check the field in Profile schema.

A profile name instead of a path

Node code APOSTATE_CATALOGUE_PROFILE_IDS_RETIRED. Cause. profile is a string that does not look like a path. A string counts as a path when it ends in .json, contains a slash, starts with . or is absolute. Fix. Pass the file’s path, such as ./profiles/desktop.json, or the profile as a dict or object. To pick a persona, use fingerprint_platform.

No driver installed

Node says npm install patchright and throws BrowserLaunchError. Cause. Patchright is missing or broken, which means a partial install. Fix. Reinstall it as the message says. Neither package needs playwright install.

Installing the browser

Installation covers the cache, mirrors and offline installs.

Nothing to download

Cause. The package has no pinned manifest for this target, and the release manifest could not be fetched, usually because GitHub is unreachable. Fix. Check that the host can reach github.com, or point APOSTATE_BINARY at a browser you unpacked yourself.

A download that does not match

Node says SHA-256 mismatch for apostate-152.0.7977.83-linux-x64.tar.zst. Cause. The download was cut short or corrupted, or a mirror in APOSTATE_DOWNLOAD_BASE_URL serves other bytes. Fix. Run apostate install again, and check the mirror.

A host with no build

Cause. The host is not Linux x64, Linux arm64, macOS on Apple silicon or Windows x64, such as an Intel Mac. Fix. Run on a supported host.

No zstd on Linux

Cause. The Linux archives are .tar.zst. Python before 3.14 and Node before 22.15 cannot decompress zstd on their own. Fix. Install zstd (apt install zstd), or use the newer runtime.

GNU tar and a zip archive (Node on Windows)

Cause. The Node package extracts the Windows and macOS zip archives with tar, and GNU tar cannot read zip. Fix. Put Windows’ own tar.exe (bsdtar) first on PATH.

Downloading through a proxy (Node)

BinaryDownloadError, code BINARY_DOWNLOAD_FAILED. Cause. A launch with proxy on a machine without the browser. The Node package does not download through the proxy. Fix. Run npx apostate install once without the proxy, or pass a download function that fetches through it.

A named browser that is not there

Node says the configured path for executablePath and binaryPath. Cause. APOSTATE_BINARY, binary_path or executablePath names a path with no browser. Fix. Name the executable, the .app bundle or the directory the archive unpacks to, or unset the variable.

Running

Xvfb is missing

Node says headless: true. Cause. A launch with headless off on a Linux host with no display. The package starts Xvfb for it, and Xvfb is not installed. Fix. apt install xvfb, or launch headless. Linux servers has the details.

The GeoIP lookup failed

A warning, not an error. The launch goes ahead. From 0.4.4 the Python package prints:
Node prints the same text after [Apostate], with Node’s own connection error, such as connect ECONNREFUSED 127.0.0.1:9. Both packages also put the warning in the launch’s diagnostics: apostate_diagnostics["warnings"] in Python from 0.4.4, apostateDiagnostics.warnings in Node. A similar warning says when the lookup answered without a country or a timezone. In 0.4.3 the second half of the message says the launch keeps the host’s own locale. That is wrong. The persona uses en-US, as the 0.4.4 text says. Cause. The lookup could not reach any endpoint, or the proxy refused the connection. The persona then uses en-US and the host’s timezone, which behind a proxy is not the exit’s. Fix. Check the proxy, or pass locale and timezone yourself. Locale and timezone covers the lookup.

The browser did not start

Cause. The driver or the browser failed after the package handed over, for example because the browser refused a switch. The driver’s message follows, with any proxy URL removed. From 0.4.4 the --apostate-profile value in it reads --apostate-profile=<redacted>. Fix. Run the same switches as apostate run -- <switches> --fingerprint-explain to see the browser’s own apostate: message.