{"record":{"id":"05365eb4ab57e9c9","repo":"denoland/deno","slug":"callback-must-be-a-function","errorCode":null,"errorMessage":"callback must be a function","messagePattern":"callback must be a function","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/web/locks.js","lineNumber":114,"sourceCode":"    webidl.illegalConstructor();\n  }\n\n  async request(name, optionsOrCallback, callback = undefined) {\n    webidl.assertBranded(this, LockManagerPrototype);\n\n    const prefix = \"Failed to execute 'request'\";\n    webidl.requiredArguments(arguments.length, 2, prefix);\n\n    let options;\n    if (arguments.length === 2) {\n      options = {};\n      callback = optionsOrCallback;\n    } else {\n      options = optionsOrCallback;\n    }\n\n    if (typeof callback !== \"function\") {\n      throw new TypeError(\"callback must be a function\");\n    }\n\n    options = webidl.converters.LockOptions(\n      options,\n      prefix,\n      \"Argument 2\",\n    );\n\n    if (StringPrototypeStartsWith(name, \"-\")) {\n      throw new DOMException(\n        \"'name' must not start with '-'\",\n        \"NotSupportedError\",\n      );\n    }\n    if (options.steal && options.ifAvailable) {\n      throw new DOMException(\n        \"'steal' and 'ifAvailable' are exclusive\",\n        \"NotSupportedError\",","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/locks.js#L96-L132","documentation":"LockManager.request(name, callback) or LockManager.request(name, options, callback) requires a function as the callback that receives the held Lock. Deno throws a plain TypeError from ext/web/locks.js when the resolved callback argument is not a function. Note the argument shapes: with two arguments the second is the callback; with three, the third is — mixing up options and callback produces this error.","triggerScenarios":"navigator.locks.request(\"r\", { mode: \"shared\" }) — forgot the callback; request(\"r\", callback, options) — arguments in the wrong order so an options object lands in the callback slot; passing an async arrow stored in a variable that is actually undefined.","commonSituations":"Translating between the two- and three-argument forms during refactors; passing a method reference that got lost (undefined); passing a promise-returning expression `doWork()` instead of the function `doWork`; typed wrappers that swap parameter order.","solutions":["Check the call shape: request(name, callback) or request(name, options, callback) — the callback is always last.","Pass the function itself, not its result: `() => doWork()`, not `doWork()`.","If the callback variable can be undefined, default it or assert it before calling request.","Ensure you are not forwarding options into the callback slot when building dynamic argument lists."],"exampleFix":"// before\nnavigator.locks.request(\"res\", { mode: \"shared\" }); // no callback\n\n// after\nnavigator.locks.request(\"res\", { mode: \"shared\" }, (lock) => doWork());","handlingStrategy":"type-guard","validationCode":"function request(name, optionsOrCallback, maybeCallback) {\n  const callback = maybeCallback ?? optionsOrCallback;\n  if (typeof callback !== \"function\") {\n    throw new TypeError(\"callback must be a function\");\n  }\n  const options = maybeCallback ? optionsOrCallback : {};\n  return navigator.locks.request(name, options, callback);\n}","typeGuard":"function isLockCallback(v) {\n  return typeof v === \"function\";\n}","tryCatchPattern":"try { await navigator.locks.request(n, opts, cb); } catch (e) { if (e instanceof TypeError && e.message === \"callback must be a function\") throw new Error(`misuse of locks.request for ${n}`); throw e; }","preventionTips":["Keep the callback as the last argument in every call site.","Pass the function reference, not an invocation result.","In TypeScript, type the overloads: (name, cb) or (name, options, cb)."],"tags":["web-locks","locks","web-api","typeerror"],"backgroundTag":"callback-not-a-function","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}