denoland/deno · error

serde_v8: unknown ValueType for v8::Value

Error message

serde_v8: unknown ValueType for v8::Value

What it means

serde_v8 classifies a v8::Value into a ValueType by walking a chain of type checks (Array, BigInt, ArrayBuffer, view, Object, null/undefined, and earlier branches). This panic is the exhaustive-match guard: the value passed none of the checks. With a well-formed handle from a live isolate it is unreachable; it fires only when the handle is invalid, stale, or of a v8 kind this serde_v8 version does not know.

Source

Thrown at libs/serde_v8/payload.rs:41

      return Self::Bool;
    } else if v.is_number() {
      return Self::Number;
    } else if v.is_string() {
      return Self::String;
    } else if v.is_array() {
      return Self::Array;
    } else if v.is_big_int() {
      return Self::BigInt;
    } else if v.is_array_buffer() {
      return Self::ArrayBuffer;
    } else if v.is_array_buffer_view() {
      return Self::ArrayBufferView;
    } else if v.is_object() {
      return Self::Object;
    } else if v.is_null_or_undefined() {
      return Self::Null;
    }
    panic!("serde_v8: unknown ValueType for v8::Value")
  }
}

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Ensure every v8 handle passed to serde_v8 comes from the same live isolate and an active HandleScope
  2. Align deno_core, serde_v8, and the v8 crate versions in your lockfile
  3. In ops, take v8 values as arguments managed by deno_core instead of storing Locals yourself
  4. If versions are aligned and it still fires, report upstream with a reproducer - a v8 kind may be missing from the branch list
Defensive patterns

Strategy: type-guard

Type guard

use deno_core::v8;

enum ValueType { Number, Boolean, String, Symbol, Array, BigInt, ArrayBuffer, ArrayBufferView, Object, Null }

fn classify(v: v8::Local<v8::Value>) -> Option<ValueType> {
  if v.is_number() { Some(ValueType::Number) }
  else if v.is_boolean() { Some(ValueType::Boolean) }
  else if v.is_string() { Some(ValueType::String) }
  else if v.is_symbol() { Some(ValueType::Symbol) }
  else if v.is_array() { Some(ValueType::Array) }
  else if v.is_big_int() { Some(ValueType::BigInt) }
  else if v.is_array_buffer() { Some(ValueType::ArrayBuffer) }
  else if v.is_array_buffer_view() { Some(ValueType::ArrayBufferView) }
  else if v.is_object() { Some(ValueType::Object) }
  else if v.is_null_or_undefined() { Some(ValueType::Null) }
  else { None } // would panic in serde_v8 - reject here instead
}

Try / catch

let classified = std::panic::catch_unwind(|| serde_v8::classify(value));
if classified.is_err() {
  // treat as an isolate/handle-lifetime bug: log, drop the handle, keep the process alive
}

Prevention

When it happens

Trigger: Passing a v8::Local obtained from a different or already-disposed isolate; using a handle after GC collected the object; running a serde_v8/deno_core build whose version predates a value kind added in the vendored v8.

Common situations: Embedder bugs that store Locals across isolate teardown; mismatched deno_core/serde_v8/v8 versions in Cargo.lock; FFI code fabricating handles.

Related errors


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