denoland/deno · error · anyhow::Error

Invalid serialization type

Error message

Invalid serialization type: {}

What it means

When a Deno process starts with NODE_CHANNEL_FD set — how node:child_process.fork() wires the IPC channel to the child — it also reads NODE_CHANNEL_SERIALIZATION_MODE and parses it into ChildIpcSerialization, which accepts exactly "json" or "advanced" (FromStr in ext/node/ops/ipc.rs:11-23, wired from cli/lib/args.rs:56-68). Any other string aborts startup with "Invalid serialization type: {s}". fork() itself validates the option, so this almost always comes from hand-rolled spawns that set the env vars directly.

Solutions

  1. Use one of the two accepted lowercase values: NODE_CHANNEL_SERIALIZATION_MODE=json or =advanced.
  2. If the child should not have IPC at all, unset both NODE_CHANNEL_FD and NODE_CHANNEL_SERIALIZATION_MODE in the spawn env.
  3. Prefer node:child_process.fork() from a Node/Deno parent — it sets the env correctly and validates the option for you.

Example fix

// before
spawn('deno', ['child.ts'], {
  env: { ...process.env, NODE_CHANNEL_FD: '3', NODE_CHANNEL_SERIALIZATION_MODE: 'JSON' },
});
// child dies at startup: Invalid serialization type: JSON

// after
spawn('deno', ['child.ts'], {
  env: { ...process.env, NODE_CHANNEL_FD: '3', NODE_CHANNEL_SERIALIZATION_MODE: 'json' },
});
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate the env before spawning a Deno child with an IPC channel
const modes = new Set(["json", "advanced"]);
const mode = process.env.NODE_CHANNEL_SERIALIZATION_MODE;
if (process.env.NODE_CHANNEL_FD && (mode !== undefined) && !modes.has(mode)) {
  throw new Error(`NODE_CHANNEL_SERIALIZATION_MODE must be json|advanced, got ${mode}`);
}

Type guard

type IpcSerialization = "json" | "advanced";
const isIpcSerialization = (v: string): v is IpcSerialization =>
  v === "json" || v === "advanced";

Prevention

When it happens

Trigger: Spawning deno manually with NODE_CHANNEL_FD=3 and NODE_CHANNEL_SERIALIZATION_MODE=JSON (wrong case), or values like ini/v8/serialize; forwarding an unvalidated serialization setting from a parent tool to a Deno child meant to speak process.send().

Common situations: Replacing a Node child with a Deno child in an existing fork harness; test runners that emulate fork via env; documentation examples that set the var with the wrong casing or a Node-internal name.

Understand the failure class

Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/af91e3a0d29070b0. Report an issue: GitHub.

Appendix: source

Thrown at ext/node/ops/ipc.rs:17

// Copyright 2018-2026 the Deno authors. MIT license.

pub use impl_::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ChildIpcSerialization {
  Json,
  Advanced,
}

impl std::str::FromStr for ChildIpcSerialization {
  type Err = deno_core::anyhow::Error;
  fn from_str(s: &str) -> Result<Self, Self::Err> {
    match s {
      "json" => Ok(ChildIpcSerialization::Json),
      "advanced" => Ok(ChildIpcSerialization::Advanced),
      _ => Err(deno_core::anyhow::anyhow!(
        "Invalid serialization type: {}",
        s
      )),
    }
  }
}

pub struct ChildPipeFd(pub i64, pub ChildIpcSerialization);

mod impl_ {
  use std::cell::RefCell;
  use std::future::Future;
  use std::io;
  use std::rc::Rc;

  use deno_core::CancelFuture;
  use deno_core::OpState;
  use deno_core::RcRef;

View on GitHub (pinned to 9ad36f7a2c)