ComposioHQ/composio · error · ComposioInvalidModifierError

Invalid afterExecute modifier. Not a function.

Error message

Invalid afterExecute modifier. Not a function.

What it means

ComposioInvalidModifierError thrown by applyAfterExecuteModifiers when the afterExecute modifier configured on the tool/Composio instance is present but not a function. The SDK validates modifier callables before invoking them to avoid a less clear TypeError at call time.

Source

Thrown at ts/packages/core/src/models/Tools.ts:421

    if (this.autoUploadDownloadFiles) {
      const fileToolModifier = new FileToolModifier(this.client, this.fileUploadPathOptions);
      modifiedResult = await fileToolModifier.fileDownloadModifier(tool, {
        toolSlug,
        toolkitSlug,
        result: modifiedResult,
        signal: requestOptions?.signal,
      });
    }
    // apply the after execute modifiers
    if (modifier) {
      if (typeof modifier === 'function') {
        modifiedResult = await modifier({
          toolSlug,
          toolkitSlug,
          result: modifiedResult,
        });
      } else {
        throw new ComposioInvalidModifierError('Invalid afterExecute modifier. Not a function.');
      }
    }

    return modifiedResult;
  }

  /**
   * Lists Composio API tools available to the SDK.
   *
   * This method fetches remote Composio tools from the API in raw format. The response can be
   * filtered and modified as needed. Local experimental custom tools are session-scoped; attach
   * them when creating or reusing a Tool Router session, then use `session.tools()`,
   * `session.customTools()`, or `session.execute()`.
   * It provides access to the underlying tool data without provider-specific wrapping.
   *
   * @param {ToolListParams} query - Query parameters to filter the tools (required)
   * @param {GetRawComposioToolsOptions} [options] - Optional configuration for tool retrieval
   * @param {TransformToolSchemaModifier} [options.modifySchema] - Function to transform tool schemas

View on GitHub (pinned to 64b1b85502)

Solutions

  1. Verify afterExecute is an async (result) => result-style function
  2. Log typeof your afterExecute value before wiring it
  3. Update to the current modifier signature: ({ toolSlug, toolkitSlug, result }) => result

Example fix

// before
.with({ afterExecute: { result } => result })
// after
.with({ afterExecute: async ({ result }) => result })
Defensive patterns

Strategy: validation

Validate before calling

if (typeof afterExecute !== 'function') throw new TypeError('afterExecute must be a function');

Type guard

const isModifierFn = (m: unknown): m is ({ result }: { result: unknown }) => Promise<unknown> => typeof m === 'function';

Try / catch

try { await tool.execute(args); } catch (e) { if (e instanceof ComposioInvalidModifierError) fixModifierConfig(); else throw e; }

Prevention

When it happens

Trigger: Passing a non-function afterExecute modifier, e.g. .with({ afterExecute: { fn: ... } }) or withModifiers({ afterExecute: null }) / a string / an object instead of a callback, then calling executeWithTool.

Common situations: Serializing modifiers from config/JSON, passing a modifier object shape from another SDK version, destructuring mistakes producing undefined wrapped in an object, copy-pasting modifier config from docs of a different version.

Related errors


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