{"record":{"id":"47ba4c4bce82054f","repo":"dotnet/aspnetcore","slug":"the-value-identifier-is-not-a-function","errorCode":null,"errorMessage":"The value '${identifier}' is not a function.","messagePattern":"The value '(.+?)' is not a function\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts","lineNumber":629,"sourceCode":"      ];\n  }\n\n  // Takes an object member and a call type and returns a function that performs the operation specified by the call type on the member.\n  //\n  // @param parent Immediate parent of the accessed object member.\n  // @param memberName Name (key) of the accessed member.\n  // @param callType The type of the operation to perform on the member.\n  // @param identifier The full member identifier. Only used for error messages.\n  // @returns A function that performs the operation on the member.\n  //\n  function wrapJSCallAsFunction(parent: any, memberName: string, callType: JSCallType, identifier: string): Function {\n      switch (callType) {\n      case JSCallType.FunctionCall:\n          const func = parent[memberName];\n          if (func instanceof Function) {\n              return func.bind(parent);\n          }\n          throw new Error(`The value '${identifier}' is not a function.`);\n\n      case JSCallType.ConstructorCall:\n          const ctor = parent[memberName];\n          if (ctor instanceof Function) {\n              const bound = ctor.bind(parent);\n              return (...args: any[]) => new bound(...args);\n          }\n          throw new Error(`The value '${identifier}' is not a function.`);\n\n      case JSCallType.GetValue:\n          if (!isReadableProperty(parent, memberName)) {\n              throw new Error(`The property '${identifier}' is not defined or is not readable.`);\n          }\n          return () => parent[memberName];\n      case JSCallType.SetValue:\n          if (!isWritableProperty(parent, memberName)) {\n              throw new Error(`The property '${identifier}' is not writable.`);\n          }","sourceCodeStart":611,"sourceCodeEnd":647,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts#L611-L647","documentation":"Thrown by wrapJSCallAsFunction for JSCallType.FunctionCall: the member resolved from the identifier exists but is not an instance of Function. The framework calls func.bind(parent) and invokes it; a non-callable value (number, object, getter that returns a non-function) cannot be invoked.","triggerScenarios":"Calling .invokeMethod('myLib.value') where 'value' is a property holding data, not a function; invoking a getter; calling a key that holds an object/array. Distinguish from error 84 (missing) — here the member exists but is not callable.","commonSituations":"Naming collision between a data property and the function you meant to call; refactor that turned a function into a property; calling a namespace object as if it were a function.","solutions":["Check the JS exports: ensure the identifier points to a function (typeof x === 'function').","Rename so the function and the data property do not collide.","If you meant to read a value, use the read/get path instead of the call path on the .NET side.","Add a thin wrapper function in JS that returns the value."],"exampleFix":"// before\n// lib.js\nexport const count = 0; // data, not fn\n// C#: await JS.InvokeAsync<int>(\"lib.count\");\n\n// after\n// lib.js\nexport function getCount() { return 0; }\n// C#: await JS.InvokeAsync<int>(\"lib.getCount\");","handlingStrategy":"type-guard","validationCode":"// shim: assert callable before exposing\nexport function ensureFn(obj, id) {\n  const fn = id.split('.').reduce((o,k)=>o?.[k], obj);\n  if (typeof fn !== 'function') throw new TypeError(`${id} is not a function`);\n  return fn;\n}","typeGuard":"function isCallable(v: any): v is Function { return typeof v === 'function'; }","tryCatchPattern":"try { await JS.InvokeAsync('lib.fn'); } catch (e) { if (/is not a function/i.test(e.message)) { /* fix identifier */ } else throw e; }","preventionTips":["Audit JS exports: each invoked identifier must be a function.","Avoid name collisions between data and function exports.","Add unit tests asserting typeof === 'function' on exported members."],"tags":["blazor","jsinterop","type-mismatch","invocation"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}