Skip to content

Import crashes on runtimes where process.pid is undefined (global["undefined"] is read-only) #529

Description

@ninth-planet

Summary

pkijs's crypto-engine registry stores its state at global[process.pid] (in initCryptoEngine / setEngine / getEngine). On runtimes where a process object exists but process.pid is undefined — notably current Supabase Edge Functions (Deno-based, exposing a partial process shim) — the property key evaluates to the string "undefined":

global[process.pid] = ...   // → global["undefined"] = ...

globalThis.undefined is a non-writable, non-configurable property of every global object, so the assignment throws:

TypeError: Cannot assign to read only property 'undefined' of object '#<Window>'

Because this happens at module load time, merely import-ing pkijs (directly or transitively) kills the whole isolate before any user code runs.

Impact

  • Affects 3.3.3 and 3.4.0 identically (verified against the published tarballs — the process.pid guard is unchanged between them).
  • On 2026-08-14 this took down three production Supabase edge functions at our org (plus two latent importers) for ~44 minutes. Nothing in our code had changed — a redeploy simply landed on a runtime revision where process.pid was undefined.
  • Subtle failure mode: in that environment pkijs loads as CJS with its own injected global, while ES-module code sees a different global shape — so naive attempts to patch globalThis from application code silently do nothing. The only reliable workaround is defining a numeric own process.pid before pkijs loads.

Minimal repro

Simulated in plain Node (mirrors what the Deno shim exposes) — verified against the published pkijs@3.4.0 tarball:

// repro.mjs — node >= 18
Object.defineProperty(process, "pid", { value: undefined, configurable: true });
await import("pkijs"); // TypeError: Cannot assign to read only property 'undefined'

Output:

TypeError: Cannot assign to read only property 'undefined' of object '#<Object>'

The same script with an unmodified process.pid imports cleanly. The offending lines in the published build (node_modules/pkijs/build/index.js:6794-6799):

if (typeof global[process.pid] === "undefined") {
    global[process.pid] = {};
}
else {
    if (typeof global[process.pid] !== "object") {
        throw new Error(`Name global.${process.pid} already exists and it is not an object`);

On an actual Supabase Edge Function, a bare import * as pkijs from "npm:pkijs"; is sufficient to crash the isolate at boot when the runtime reports no pid.

Suggested fix

In the engine registry, don't trust process.pid to be a usable key:

const engineKey =
  typeof process !== "undefined" && Number.isInteger(process?.pid)
    ? process.pid
    : Symbol.for("pkijs.engine"); // fixed fallback key

(or any fixed string/symbol fallback). This keeps the current per-pid behavior on Node while making import safe on runtimes with a partial process shim.

Workaround for anyone hitting this

Define a numeric own process.pid before pkijs is imported. Our shim: supabase/functions/_shared/pkijsEdgeRuntimeShim.ts (introduced in ninth-planet/ninth-planet-publishing#626).

Happy to open a PR for the fallback-key fix if the approach is acceptable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions