ComposioHQ/composio · error · ValidationError

Ambiguous custom tool slug "${slug}". Multiple custom toolki

Error message

Ambiguous custom tool slug "${slug}". Multiple custom toolkit tools share this original slug; manual session.execute() by original slug is only supported when the original slug is unique.${hint}

What it means

When custom toolkits register tools, each gets a final namespaced slug (LOCAL_<TOOLKIT>_<TOOL>) while the original slug stays usable for manual session.execute() only if unique. If two custom toolkits expose the same original slug (case-insensitive), that slug is marked ambiguous and assertUnambiguousCustomToolSlug throws ValidationError to prevent executing an arbitrary toolkit's tool.

Source

Thrown at ts/packages/core/src/models/customToolExecution.ts:49

 * Reject ambiguous bare original slugs before falling through to backend execution.
 * Agents receive final slugs (LOCAL_<TOOLKIT>_<TOOL>) from schemas, while bare original
 * slugs are only a convenience for manual session.execute() calls when unique.
 */
export function assertUnambiguousCustomToolSlug(
  map: CustomToolsMap | undefined,
  slug: string
): void {
  if (!map) return;
  const upper = slug.toUpperCase();
  if (!map.ambiguousOriginalSlugs?.has(upper)) return;

  const finalSlugs = [...map.byFinalSlug.values()]
    .filter(entry => entry.handle.slug.toUpperCase() === upper)
    .map(entry => entry.finalSlug)
    .sort();
  const hint = finalSlugs.length ? ` Use one of: ${finalSlugs.join(', ')}.` : '';

  throw new ValidationError(
    `Ambiguous custom tool slug "${slug}". Multiple custom toolkit tools share this original slug; ` +
      `manual session.execute() by original slug is only supported when the original slug is unique.` +
      hint
  );
}

/**
 * Execute a custom tool in-process.
 * Validates input via the Zod schema, calls the user's execute function,
 * and wraps the result into the standard response format.
 *
 * Callers provide a pre-built SessionContext (which may include sibling routing).
 */
export async function executeCustomTool(
  entry: CustomToolsMapEntry,
  arguments_: Record<string, unknown>,
  sessionContext: SessionContext,
  options?: { signal?: AbortSignal }

View on GitHub (pinned to 64b1b85502)

Solutions

  1. Use the fully-qualified final slug (LOCAL_<TOOLKIT>_<TOOL>) listed in the error hint
  2. Rename one of the colliding tools in your custom toolkit definition so original slugs are unique
  3. Dynamically read final slugs from the tool schemas given to the agent instead of hardcoding bare slugs

Example fix

// before
await session.execute('GET_DATA', { userId });
// after (use the namespaced final slug from the error hint)
await session.execute('LOCAL_REPORTS_GET_DATA', { userId });
Defensive patterns

Strategy: validation

Validate before calling

const finalSlug = toolSchemas.find(t => t.slug.toUpperCase().endsWith('_GET_DATA'))?.slug;
if (!finalSlug) throw new Error('No unique tool found');
await session.execute(finalSlug, args);

Type guard

const isUnambiguousSlug = (map: CustomToolsMap | undefined, slug: string): boolean =>
  !map || !map.ambiguousOriginalSlugs?.has(slug.toUpperCase());

Try / catch

try { await session.execute(slug, args); } catch (e) { if (e instanceof ValidationError && e.message.includes('Ambiguous custom tool slug')) { /* pick final slug from hint */ } throw e; }

Prevention

When it happens

Trigger: Registering two custom toolkits that both define a tool with the same original slug (e.g. 'GET_DATA'), then calling session.execute('GET_DATA') / routing execution with the bare original slug. The error is thrown by execute, routingExecuteFn, and routeMultiExecute before backend execution.

Common situations: Composing multiple third-party/custom toolkits that happen to reuse generic tool names, refactoring one toolkit into two while keeping tool names, or hardcoded slug strings in app code after adding a second toolkit.

Related errors


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