{"record":{"id":"e043942e10636067","repo":"denoland/deno","slug":"cannot-construct-unsafecallback-cannot-be-nonbloc","errorCode":null,"errorMessage":"Cannot construct UnsafeCallback: cannot be nonblocking","messagePattern":"Cannot construct UnsafeCallback: cannot be nonblocking","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/ffi/00_ffi.js","lineNumber":405,"sourceCode":"    case \"isize\":\n      return [8, 8];\n    default:\n      throw new TypeError(`Cannot get pointer size, unsupported type: ${type}`);\n  }\n}\n\nclass UnsafeCallback {\n  #refcount;\n  // Internal promise only meant to keep Deno from exiting\n  #refpromise;\n  #rid;\n  definition;\n  callback;\n  pointer;\n\n  constructor(definition, callback) {\n    if (definition.nonblocking) {\n      throw new TypeError(\n        \"Cannot construct UnsafeCallback: cannot be nonblocking\",\n      );\n    }\n    const { 0: rid, 1: pointer } = op_ffi_unsafe_callback_create(\n      definition,\n      callback,\n    );\n    this.#refcount = 0;\n    this.#rid = rid;\n    this.pointer = pointer;\n    this.definition = definition;\n    this.callback = callback;\n  }\n\n  static threadSafe(definition, callback) {\n    const unsafeCallback = new UnsafeCallback(definition, callback);\n    unsafeCallback.ref();\n    return unsafeCallback;","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/ffi/00_ffi.js#L387-L423","documentation":"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.","triggerScenarios":"new Deno.UnsafeCallback({ parameters: [...], result: 'void', nonblocking: true }, cb); reusing one shared definition object (with nonblocking: true) for both dlopen symbols and UnsafeCallback creation.","commonSituations":"A single FFI config object shared across function and callback declarations; copy-pasting a nonblocking function definition into a callback definition.","solutions":["Remove nonblocking from the callback definition object","Keep separate definition objects for dlopen functions and UnsafeCallbacks","If async behavior is needed, mark the foreign function nonblocking, not the callback"],"exampleFix":"// before\nconst cb = new Deno.UnsafeCallback(\n  { parameters: [\"i32\"], result: \"void\", nonblocking: true },\n  (n) => {},\n);\n\n// after\nconst cb = new Deno.UnsafeCallback(\n  { parameters: [\"i32\"], result: \"void\" },\n  (n) => {},\n);","handlingStrategy":"validation","validationCode":"function toCallbackDefinition(def) {\n  const { nonblocking: _, ...rest } = def; // strip FFI-function-only options\n  return rest;\n}\n\nconst cb = new Deno.UnsafeCallback(\n  toCallbackDefinition(def),\n  handler,\n);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep separate definition objects for dlopen functions and UnsafeCallbacks","never reuse a nonblocking function definition for a callback","Mark the foreign function nonblocking when you need async, not the callback"],"tags":["ffi","unsafe-callback","options"],"backgroundTag":"invalid-option-combination","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}