ComposioHQ/composio · error · Error

userId is required when custom tools are bound to a session.

Error message

userId is required when custom tools are bound to a session.

What it means

The ToolRouterSession constructor enforces that any session bound to a custom tools map must also carry a userId, because the backend needs a stable per-user identity to route and hydrate custom tools. Missing userId is a hard construction-time error.

Source

Thrown at ts/packages/core/src/models/ToolRouterSession.ts:143

  public warnings: ToolRouterSessionWarning[];
  private readonly preloadedCustomToolSlugs: string[];
  private readonly inlineCustomToolsPayload: ToolRouterSessionMetadata['inlineCustomToolsPayload'];

  /** Singleton session context — shared across all custom tool executions */
  private readonly sessionContext?: SessionContext;

  constructor(
    private readonly client: ComposioClient,
    private readonly config: ComposioConfig<TProvider> | undefined,
    sessionId: string,
    mcp: ToolRouterMCPServerConfig,
    experimentalOverrides?: Pick<SessionExperimental, 'assistivePrompt'>,
    private readonly customToolsMap?: CustomToolsMap,
    private readonly userId?: string,
    metadata?: ToolRouterSessionMetadata
  ) {
    if (customToolsMap && !userId) {
      throw new Error('userId is required when custom tools are bound to a session.');
    }
    this.sessionId = sessionId;
    this.mcp = mcp;
    this.experimental = {
      assistivePrompt: experimentalOverrides?.assistivePrompt,
      files: new ToolRouterSessionFilesMount(client, sessionId),
    };
    this.preload = metadata?.preload ?? { tools: [] };
    this.sandbox = metadata?.workbench;
    this.configVersion = metadata?.configVersion;
    this.warnings = metadata?.warnings ?? [];
    this.preloadedCustomToolSlugs = metadata?.preloadedCustomToolSlugs ?? [];
    this.inlineCustomToolsPayload = metadata?.inlineCustomToolsPayload;

    // Create singleton session context if custom tools are bound
    if (customToolsMap && userId) {
      this.sessionContext = new SessionContextImpl(
        client,

View on GitHub (pinned to 64b1b85502)

Solutions

  1. Pass userId whenever custom tools are bound: composio.sessions.create({ userId, ... })
  2. If you don't need custom tools on that session, remove them so the map isn't bound
  3. Audit all session-creation call sites for a consistent userId

Example fix

// before
await composio.sessions.create({ tools: [customTool] });
// after
await composio.sessions.create({ userId: 'user-42', tools: [customTool] });
Defensive patterns

Strategy: validation

Validate before calling

const usesCustomTools = tools.some(t => isCustomTool(t));
if (usesCustomTools && !userId) throw new Error('userId required with custom tools');
await composio.sessions.create({ userId, tools });

Type guard

const needsUserId = (tools: unknown[]): boolean => tools.some(isCustomTool);

Try / catch

try { const s = await composio.sessions.create(cfg); } catch (e) { if (/userId is required/.test(String(e?.message))) { return composio.sessions.create({ ...cfg, userId: currentUserId }); } throw e; }

Prevention

When it happens

Trigger: Internally constructing (via SDK flows like session hydration) a ToolRouterSession with a customToolsMap but no userId — typically caused by user code creating sessions with custom tools while omitting the userId parameter in the session/config options.

Common situations: Adding custom tools to a session config and forgetting to pass userId; multi-user server where userId plumbing was skipped in one code path; upgrading to an SDK version that made userId mandatory with custom tools.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28). Data as JSON: /api/errors/e5ea0ec146512ec1. Report an issue: GitHub.