denoland/deno · error · TypeError

Cannot construct UnsafeCallback: cannot be nonblocking

Error message

Cannot construct UnsafeCallback: cannot be nonblocking

What it means

Deno.UnsafeCallback(definition, callback) creates a native trampoline that must invoke JS on a live runtime thread. The nonblocking option exists for dlopen function symbols (run the foreign call on the thread pool); it has no meaning for callbacks and is rejected at construction time.

Solutions

  1. Remove nonblocking from the callback definition object
  2. Keep separate definition objects for dlopen functions and UnsafeCallbacks
  3. If async behavior is needed, mark the foreign function nonblocking, not the callback

Example fix

// before
const cb = new Deno.UnsafeCallback(
  { parameters: ["i32"], result: "void", nonblocking: true },
  (n) => {},
);

// after
const cb = new Deno.UnsafeCallback(
  { parameters: ["i32"], result: "void" },
  (n) => {},
);
Defensive patterns

Strategy: validation

Validate before calling

function toCallbackDefinition(def) {
  const { nonblocking: _, ...rest } = def; // strip FFI-function-only options
  return rest;
}

const cb = new Deno.UnsafeCallback(
  toCallbackDefinition(def),
  handler,
);

Prevention

When it happens

Trigger: new Deno.UnsafeCallback({ parameters: [...], result: 'void', nonblocking: true }, cb); reusing one shared definition object (with nonblocking: true) for both dlopen symbols and UnsafeCallback creation.

Common situations: A single FFI config object shared across function and callback declarations; copy-pasting a nonblocking function definition into a callback definition.

Related errors


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

Appendix: source

Thrown at ext/ffi/00_ffi.js:405

    case "isize":
      return [8, 8];
    default:
      throw new TypeError(`Cannot get pointer size, unsupported type: ${type}`);
  }
}

class UnsafeCallback {
  #refcount;
  // Internal promise only meant to keep Deno from exiting
  #refpromise;
  #rid;
  definition;
  callback;
  pointer;

  constructor(definition, callback) {
    if (definition.nonblocking) {
      throw new TypeError(
        "Cannot construct UnsafeCallback: cannot be nonblocking",
      );
    }
    const { 0: rid, 1: pointer } = op_ffi_unsafe_callback_create(
      definition,
      callback,
    );
    this.#refcount = 0;
    this.#rid = rid;
    this.pointer = pointer;
    this.definition = definition;
    this.callback = callback;
  }

  static threadSafe(definition, callback) {
    const unsafeCallback = new UnsafeCallback(definition, callback);
    unsafeCallback.ref();
    return unsafeCallback;

View on GitHub (pinned to 9ad36f7a2c)