{"record":{"id":"58abe7d5ed95dda6","repo":"nocodb/nocodb","slug":"integration-loader-not-available-this-node-must-b","errorCode":null,"errorMessage":"Integration loader not available. This node must be executed within a workflow context.","messagePattern":"Integration loader not available\\. This node must be executed within a workflow context\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/noco-integrations/core/src/workflow-node/types.ts","lineNumber":182,"sourceCode":"   * async run(ctx: WorkflowNodeRunContext) {\n   *   const auth = await this.getIntegration(this.config.authIntegrationId);\n   *   const data = await auth.use(async (client) => {\n   *     return client.api.getData();\n   *   });\n   * }\n   *\n   * // Loading an AI integration with type\n   * async run(ctx: WorkflowNodeRunContext) {\n   *   const ai = await this.getIntegration<AiIntegration>(this.config.aiIntegrationId);\n   *   const result = await ai.generateText({ prompt: 'Hello' });\n   * }\n   * ```\n   */\n  protected async getIntegration<T = any>(\n    integrationId: string\n  ): Promise<T> {\n    if (!this._integrationLoader) {\n      throw new Error('Integration loader not available. This node must be executed within a workflow context.');\n    }\n    return this._integrationLoader<T>(integrationId);\n  }\n\n  public abstract definition(): Promise<WorkflowNodeDefinition>;\n\n  public async validate(_config: TConfig): Promise<WorkflowNodeValidationResult> {\n    return { valid: true };\n  }\n\n  public abstract run(ctx: WorkflowNodeRunContext): Promise<WorkflowNodeResult>;\n\n  public async fetchOptions(\n    _key: string,\n    _searchQuery?: string,\n  ): Promise<unknown> {\n    return []\n  }","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/nocodb/nocodb/blob/d3caaf4e890acf64bd49b788cf6dc32b7644c895/packages/noco-integrations/core/src/workflow-node/types.ts#L164-L200","documentation":"Thrown by AbstractWorkflowNode.getIntegration when this._integrationLoader is unset. The loader is injected by the workflow executor via setIntegrationLoader before node.run()/fetchOptions() execute, so a missing loader means the node instance was used outside the executor — e.g. constructed directly in a test or called from application code rather than dispatched through the workflow runtime.","triggerScenarios":"Calling node.getIntegration('id') (transitively: node.run, node.fetchOptions, or any override that calls getIntegration) on a node instance that was constructed with `new MyNode()` directly rather than instantiated and dispatched by the workflow executor. Also when a node method is invoked before the executor has called setIntegrationLoader, or in unit tests that exercise run() without wiring the loader.","commonSituations":"Unit tests that `new MyNode()` and call .run() without injecting a loader; a node class whose fetchOptions is hit by the UI before the node is attached to a workflow; refactoring that moves getIntegration calls out of run() into a constructor/standalone helper that runs before the executor sets the loader.","solutions":["Run the node through the workflow executor (the standard path) so setIntegrationLoader is called automatically before run/fetchOptions.","In tests, call node.setIntegrationLoader(async (id) => mockIntegrationFor(id)) before invoking run/fetchOptions.","Avoid constructing workflow nodes with `new` in application code — obtain them from the workflow registry/executor.","If you genuinely need a node outside the executor, inject a loader explicitly before any method that calls getIntegration."],"exampleFix":"// before (test)\nconst node = new MyNode();\nawait node.run({}); // throws: Integration loader not available...\n\n// after\nconst node = new MyNode();\nnode.setIntegrationLoader(async (id) => mockIntegrations[id]);\nawait node.run({});","handlingStrategy":"validation","validationCode":"function nodeHasLoader(node: any): boolean {\n  return typeof node?._integrationLoader === 'function';\n}\n\nif (!nodeHasLoader(node)) {\n  throw new Error('Refusing to call run() on a node without an integration loader; run via the workflow executor.');\n}","typeGuard":"function isDispatchableNode<N extends { _integrationLoader?: unknown }>(\n  node: N,\n): node is N & { _integrationLoader: (id: string) => Promise<unknown> } {\n  return typeof node._integrationLoader === 'function';\n}","tryCatchPattern":"try {\n  await node.run(ctx);\n} catch (err) {\n  if (err instanceof Error && /Integration loader not available/.test(err.message)) {\n    // surface 'attach this node to a workflow first' to the user / test author\n    throw new Error('Node must be executed within a workflow context');\n  }\n  throw err;\n}","preventionTips":["Always obtain nodes from the workflow executor, not via `new`.","In tests, call node.setIntegrationLoader(...) before run/fetchOptions.","Treat getIntegration as executor-only and document it on the node class."],"tags":["workflow","integrations","lifecycle","typescript"],"backgroundTag":null,"analyzedSha":"d3caaf4e890acf64bd49b788cf6dc32b7644c895","analyzedAt":"2026-08-12T13:07:32.092Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}