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
- Pass userId whenever custom tools are bound: composio.sessions.create({ userId, ... })
- If you don't need custom tools on that session, remove them so the map isn't bound
- 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
- Always pass userId when configuring custom tools
- Centralize session creation in one helper that enforces userId
- Add a lint/review rule for custom-tool configs
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
- Custom tool slugs are not supported in preload.tools: ${cust
- A provider is required when using custom tools with session.
- Custom tool slug collision: "${finalSlug}" is already regist
- Custom tool slug collision: original slug "${handle.slug}" i
- Invalid proxy execute parameters
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/e5ea0ec146512ec1.
Report an issue: GitHub.