denoland/deno · error

nul byte found in provided data

Error message

nul byte found in provided data

What it means

On Windows, Deno builds the child-process environment block by encoding every variable name and value as NUL-terminated UTF-16 in make_envp(). Before that, ensure_no_nuls() scans each key and value and rejects any that already contain a U+0000, because an embedded NUL would terminate the entry early and silently corrupt the rest of the block. The failure surfaces from Deno.Command spawn as an InvalidInput error ('nul byte found in provided data').

Source

Thrown at runtime/subprocess_windows/src/env.rs:227

// they are compared using a caseless string mapping.
impl From<OsString> for EnvKey {
  fn from(k: OsString) -> Self {
    EnvKey {
      utf16: k.encode_wide().collect(),
      os_string: k,
    }
  }
}

impl From<&OsStr> for EnvKey {
  fn from(k: &OsStr) -> Self {
    Self::from(k.to_os_string())
  }
}

pub fn ensure_no_nuls<T: AsRef<OsStr>>(s: T) -> io::Result<T> {
  if s.as_ref().encode_wide().any(|b| b == 0) {
    Err(io::Error::new(
      io::ErrorKind::InvalidInput,
      "nul byte found in provided data",
    ))
  } else {
    Ok(s)
  }
}

pub fn make_envp(
  maybe_env: Option<BTreeMap<EnvKey, OsString>>,
) -> io::Result<(*mut c_void, Vec<u16>)> {
  // On Windows we pass an "environment block" which is not a char**, but
  // rather a concatenation of null-terminated k=v\0 sequences, with a final
  // \0 to terminate.
  if let Some(env) = maybe_env {
    let mut blk = Vec::new();

    // If there are no environment variables to set then signal this by

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Strip or reject U+0000 in every env key and value before passing env to Deno.Command
  2. Pass binary data via stdin, a temp file, or argv instead of environment variables
  3. Add a spawn smoke test that uses the exact env map your app builds so NULs are caught before deployment

Example fix

// before
const cmd = new Deno.Command("cmd.exe", {
  env: { TOKEN: "abc\u0000def" }, // embedded NUL -> spawn fails
});
const child = cmd.spawn();

// after
const clean = (s: string) => s.replaceAll("\u0000", "");
const env = Object.fromEntries(
  Object.entries(rawEnv).map(([k, v]) => [clean(k), clean(String(v))]),
);
const cmd = new Deno.Command("cmd.exe", { env });
const child = cmd.spawn();
Defensive patterns

Strategy: validation

Validate before calling

const hasNul = (s: string) => s.includes("\u0000");
function assertCleanEnv(env: Record<string, string>) {
  for (const [k, v] of Object.entries(env)) {
    if (hasNul(k) || hasNul(v)) {
      throw new Error(`NUL byte in environment entry: ${JSON.stringify(k)}`);
    }
  }
}
// assertCleanEnv(env) before new Deno.Command(prog, { env })

Try / catch

try {
  const child = cmd.spawn();
} catch (err) {
  if (err instanceof TypeError && err.message.includes("nul byte")) {
    // sanitize env (strip U+0000) and retry spawn
  } else throw err;
}

Prevention

When it happens

Trigger: Calling new Deno.Command(prog, { env: {...} }).spawn() / .output() on Windows when any env key or value contains a NUL character, e.g. env: { TOKEN: "a\u0000b" }. make_envp() runs ensure_no_nuls() over every entry of the env map supplied to the spawn options.

Common situations: Env values copied verbatim from binary files, protobuf/length-prefixed buffers, or Windows registry strings that carry embedded NUL terminators; passing serialized data through environment variables; strings assembled with String.fromCharCode(0).

Related errors


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