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 schemasView on GitHub (pinned to 64b1b85502)
Solutions
- Verify afterExecute is an async (result) => result-style function
- Log typeof your afterExecute value before wiring it
- 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
- Type modifiers explicitly at the config boundary
- Never load modifiers from JSON without a typeof check
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
- Invalid beforeExecute modifier. Not a function.
- Invalid schema modifier. Not a function.
- experimental_subAgent() target must be "claude", "codex", or
- Invalid Composio CLI release tag: ${releaseTag}
- Invalid
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/a24807296c698ae3.
Report an issue: GitHub.