denoland/deno · critical
unable to convert
Error message
unable to convert
What it means
The second failure mode of bindings::get(): the property at the given path exists, but converting the v8 value to the expected Rust type (v8::Object, v8::Function, etc. via TryInto) fails, so the "unable to convert" panic fires. This means the global shape is present but wrong: something replaced a binding with a value of a different type before deno_core grabbed it. Typical sources are user/middleware JavaScript overwriting internals, or a snapshot from an incompatible deno_core version where the path holds a different kind of value.
Source
Thrown at libs/core/runtime/bindings.rs:316
)
}
}
pub(crate) fn get<'s, 'i, T>(
scope: &mut v8::PinScope<'s, 'i>,
from: v8::Local<'s, v8::Object>,
key: FastStaticString,
path: &'static str,
) -> T
where
v8::Local<'s, v8::Value>: TryInto<T>,
{
let key = key.v8_string(scope).unwrap();
from
.get(scope, key.into())
.unwrap_or_else(|| panic!("{path} exists"))
.try_into()
.unwrap_or_else(|_| panic!("unable to convert"))
}
/// Create an object on the `globalThis` that looks like this:
/// ```ignore
/// globalThis.Deno = {
/// core: {
/// ops: {},
/// },
/// // console from V8
/// console,
/// // wrapper fn to forward message to V8 console
/// callConsole,
/// };
/// ```
pub(crate) fn initialize_deno_core_namespace<'s, 'i>(
scope: &mut v8::PinScope<'s, 'i>,
context: v8::Local<'s, v8::Context>,
init_mode: InitMode,View on GitHub (pinned to 336da420f4)
Solutions
- Find the code that overwrites the binding and make it extend the existing object instead of replacing it
- Regenerate the startup snapshot with the same deno_core version as the binary so every binding has the expected type
- Audit global_object_middlewares for code that runs before init and returns/sets different types
- If patching is required, do it after JsRuntime initialization completes, not during startup
Example fix
// before (startup script runs before core grabs bindings):
globalThis.Deno = { core: { ops: 'shim' } }; // replaces real objects with a string
// after: extend, never replace
const deno = globalThis.Deno;
globalThis.Deno = { ...deno, extraFlag: true }; Defensive patterns
Strategy: validation
Validate before calling
// Guard in bootstrap scripts: verify the binding shape before touching it.
if (typeof globalThis.Deno?.core?.ops !== 'object' || globalThis.Deno.core.ops === null) {
throw new Error('Deno.core.ops missing or wrong type; refusing to patch');
} Type guard
// TypeScript: narrow before patching internals
function hasDenoCore(v: unknown): v is { core: { ops: Record<string, unknown> } } {
return !!v && typeof v === 'object'
&& 'core' in v && typeof (v as any).core === 'object'
&& 'ops' in (v as any).core && typeof (v as any).core.ops === 'object';
} Prevention
- Extend existing globals (spread) instead of replacing them
- Apply monkey-patches after JsRuntime initialization completes, never during startup
- Regenerate snapshots on every deno_core bump so binding types stay in sync
- Add a startup assertion that required bindings exist and have the expected types
When it happens
Trigger: A startup script or global_object_middleware assigning a non-object to globalThis.Deno.core (e.g. a string or plain shim) before runtime init; a snapshot built by a deno_core version where an expected Function binding (event loop tick, timers, error constructors) was an Object or undefined; JS running between context creation and bindings::get that mutates Deno internals.
Common situations: Embedders monkey-patching Deno.core in bootstrap code; snapshot/binary version skew after a dependency bump; polyfill libraries loaded eagerly that replace built-ins wholesale instead of extending them.
Related errors
- {path} exists
- Failed to initialize a JsRuntime: {}
- Invalid data type at index {id}, expected '{}'
- Failed to initialize JsRuntime for snapshotting: {:?}
- Attempted to read snapshot data out of range: {id} (of {})
AI-assisted analysis of denoland/deno@336da420f4 (2026-08-20).
Data as JSON: /api/errors/d1cfb0d41c67d118.
Report an issue: GitHub.