{"record":{"id":"b8e69ba561c4cb29","repo":"ComposioHQ/composio","slug":"a-provider-is-required-when-using-custom-tools-wit","errorCode":null,"errorMessage":"A provider is required when using custom tools with session.tools(). Pass a provider in the Composio constructor.","messagePattern":"A provider is required when using custom tools with session\\.tools\\(\\)\\. Pass a provider in the Composio constructor\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ts/packages/core/src/models/ToolRouterSession.ts","lineNumber":230,"sourceCode":"        if (toolSlug === COMPOSIO_MULTI_EXECUTE_TOOL) {\n          return this.routeMultiExecute(input, ToolsModel, rawTools, modifiers);\n        }\n        const customTool = findCustomTool(this.customToolsMap, toolSlug);\n        if (customTool) {\n          return executeCustomTool(customTool, input, this.sessionContext!);\n        }\n        assertUnambiguousCustomToolSlug(this.customToolsMap, toolSlug);\n        return this.executeBackendSessionTool(\n          ToolsModel,\n          toolSlug,\n          input,\n          modifiers,\n          rawToolBySlug.get(toolSlug.toUpperCase())\n        );\n      };\n\n      if (!this.config?.provider) {\n        throw new Error(\n          'A provider is required when using custom tools with session.tools(). ' +\n            'Pass a provider in the Composio constructor.'\n        );\n      }\n      return this.config.provider.wrapTools(sessionTools, routingExecuteFn) as ReturnType<\n        TProvider['wrapTools']\n      >;\n    }\n\n    // Standard path (no local tools)\n    const wrappedTools = modifiers?.modifySchema\n      ? ToolsModel.wrapToolsForToolRouter(this.sessionId, sessionTools, modifiers, rawTools)\n      : ToolsModel.wrapToolsForToolRouter(this.sessionId, sessionTools, modifiers);\n    return wrappedTools as ReturnType<TProvider['wrapTools']>;\n  }\n\n  private async applySchemaModifier(\n    tools: Tool[],","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/ts/packages/core/src/models/ToolRouterSession.ts#L212-L248","documentation":"session.tools() needs to wrap tool results through a provider adapter, but the Composio client was constructed without a provider. When custom tools are in play, the SDK requires a provider (passed to the Composio constructor) to call wrapTools, so it throws instead of returning incorrectly wrapped tools.","triggerScenarios":"Creating `new Composio({ apiKey })` with no provider, binding custom tools to a session, then calling session.tools() — the code path hits the `if (!this.config?.provider)` check before provider.wrapTools.","commonSituations":"Using the SDK purely as an API client then later adding custom tools; provider passed to a different Composio instance than the one used for the session; examples copied from provider-less quickstarts extended with custom tools.","solutions":["Pass a provider when constructing Composio: new Composio({ apiKey, provider: new OpenAIProvider(...) })","Ensure the same provider-configured client instance is used to create/retrieve the session","If you never use custom tools, remove them so the provider branch isn't required"],"exampleFix":"// before\nconst composio = new Composio({ apiKey });\n// after\nconst composio = new Composio({ apiKey, provider: new OpenAIProvider({ apiKey: openaiKey }) });","handlingStrategy":"validation","validationCode":"const hasProvider = (c: Composio) => Boolean((c as any).config?.provider);\nif (!hasProvider(composio)) throw new Error('provider required for session.tools() with custom tools');","typeGuard":"const supportsCustomToolSessions = (c: Composio): boolean => Boolean((c as any).config?.provider);","tryCatchPattern":"try { const t = await session.tools(); } catch (e) { if (/provider is required/.test(String(e?.message))) { throw new Error('Re-create Composio with a provider'); } throw e; }","preventionTips":["Construct Composio with a provider from day one","Share one configured client instance across session flows","Decide upfront whether custom tools are in scope and configure accordingly"],"tags":["session","custom-tools","provider","configuration","typescript"],"backgroundTag":"missing-required-parameter","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}