Skip to content

Troubleshooting & FAQ

Common issues and solutions for Matimo 0.2.0 (TypeScript & Python). Upgrading from 0.1.x? Start with Governance in 0.2.0.

Error: Node.js 22.19+ required. You are running v20.x.x (from matimo doctor), or an EBADENGINE warning from npm/pnpm

Since 0.3.0 every @matimo/* package needs Node 22.19 or newer. Node 18 and 20 are no longer supported.

Solution:

Terminal window
node --version
# If below v22.19, install from https://nodejs.org
# Use nvm (Node Version Manager) for easy switching:
nvm install 22
nvm use 22

Error: pnpm: command not found

Solution:

Terminal window
npm install -g pnpm@8.15.0
pnpm --version

Error: Found X errors in src/**

Solution:

Terminal window
# Clear and rebuild
pnpm clean
pnpm install
pnpm build
# If still failing, check TypeScript version
pnpm list typescript
# Should be 5.9.3 or higher

Error: ModuleNotFoundError: No module named 'matimo' or Python 3.10 or lower detected

Solution:

Terminal window
python --version
# If < 3.11, upgrade:
# macOS: brew install python@3.11
# Linux: sudo apt install python3.11
# Windows: https://www.python.org/downloads/
# Verify:
python3.11 --version
# Create virtual environment
python3.11 -m venv venv
source venv/bin/activate # or 'venv\Scripts\activate' on Windows

Error: ERROR: Could not find a version that satisfies the requirement

Solution:

Terminal window
# Make sure you're using Python 3.11+
python --version
# Try with uv (faster):
uv add matimo # Creates venv automatically
# Or explicit pip:
pip install --upgrade pip
pip install matimo
# For specific version:
pip install matimo==0.2.0

Error: ModuleNotFoundError: No module named 'langchain' / ModuleNotFoundError: No module named 'crewai'

Solution:

Terminal window
# Install with extras:
pip install "matimo-core[langchain]"
#or
pip install "matimo-core[crewai]"
# With uv:
uv add "matimo-core[langchain]"
uv add "matimo-core[crewai]"
# Verify:
python -c "from matimo.integrations.langchain import convert_tools_to_langchain; print('LangChain integration available')"

Error: RuntimeError: asyncio.run() cannot be called from a running event loop

Solution: Jupyter already runs an event loop, so use top-level await instead of asyncio.run():

from matimo import Matimo
matimo = await Matimo.init()

If you have to call asyncio.run() (for example in code shared with a script), install nest_asyncio and apply it first:

Terminal window
pip install nest_asyncio
import nest_asyncio
nest_asyncio.apply()

Error: Tool execution timeout or Tool not callable

Solution:

# Verify tools are created correctly
tools = convert_tools_to_crewai(tool_definitions, matimo)
print(f"Created {len(tools)} tools")
print([f"{t.name}: {t.description}" for t in tools]) # Verify names
# Ensure matimo.execute() is still available to the tool
# It's captured in the closure, so it should work

Q: Embedded code execution fails with “disabled” error

Section titled “Q: Embedded code execution fails with “disabled” error”

Error: Embedded code execution is disabled by default for security

Explanation: Matimo disables inline code execution in tool YAML to prevent Remote Code Execution (RCE) if tool definitions come from untrusted sources.

Default behavior:

// embeddedCodeDisabled = (MATIMO_ALLOW_EMBEDDED_CODE !== 'true')
// If env var is NOT set → embeddedCodeDisabled = true → throws error ✓
if (embeddedCodeDisabled) {
throw new MatimoError('Embedded code execution is disabled by default...');
}

Solutions:

  1. Recommended: Use external TypeScript files instead:
# Secure: External file
execution:
type: function
code: ./handler.ts # Version-controlled, auditable
timeout: 10000
  1. If you must use embedded code (NOT recommended):
Terminal window
# Only in trusted environments
export MATIMO_ALLOW_EMBEDDED_CODE=true
# Then run your tool
pnpm agent:factory

Q: What’s the security risk with embedded code?

Section titled “Q: What’s the security risk with embedded code?”

Risk: new Function() executes arbitrary JavaScript with access to:

  • fs module (file system read/write)
  • path module (path manipulation)
  • axios module (network requests)

If tool YAML comes from untrusted sources, an attacker could inject malicious code that:

  • Steals environment variables (tokens, keys)
  • Modifies files
  • Makes unauthorized API requests

Mitigation:

DO:

  • Use external .ts files for tool logic
  • Review all tool YAML before loading
  • Only enable embedded code in fully-trusted environments
  • Never commit embedded code to repositories

DON’T:

  • Load tool YAML from untrusted sources without review
  • Enable embedded code in production
  • Allow users to upload arbitrary tool definitions
  • Store secrets in tool YAML

Error: Tool not found: calculator

Solutions:

  1. Verify tool exists:
Terminal window
pnpm validate-tools
# Lists all loaded tools
  1. Check tools directory:
Terminal window
# Ensure tools/calculator/definition.yaml exists
ls -la tools/calculator/definition.yaml
  1. Verify tool definition:
Terminal window
pnpm validate-tools
# Shows validation errors if YAML is invalid

Error: Tool validation failed: Missing required parameter: operation

Solutions:

  1. Check tool parameters:
const tool = matimoInstance.getTool('calculator');
console.log(tool.parameters); // See required fields
  1. Verify your input matches schema:
// Wrong
await m.execute('calculator', { value: 5 });
// Correct
await m.execute('calculator', {
operation: 'add',
a: 5,
b: 3,
});
  1. Check tool spec:
Terminal window
cat tools/calculator/definition.yaml | grep -A 20 "parameters:"

Error: HTTP 401: Unauthorized

Common causes:

  1. Missing OAuth token:
Terminal window
# Set required tokens
export GMAIL_ACCESS_TOKEN=your_token
export GITHUB_TOKEN=your_token
  1. Expired token:
// Token needs refresh
const newToken = await oauth2Handler.refreshTokenIfNeeded(userId, currentToken);
  1. Wrong token format:
// Verify token is Bearer token, not full "Bearer token"
const token = process.env.GMAIL_ACCESS_TOKEN;
// Should be: "ya29.abc123..." not "Bearer ya29.abc123..."

Error: Command not found: node or shell command fails

Solutions:

  1. Verify command exists:
Terminal window
which node
which python
  1. Check working directory:
execution:
type: command
command: ./script.sh
cwd: /path/to/directory # Ensure this exists
  1. Test command manually:
Terminal window
# Test the exact command
node calculator.js --op add 5 3

Error: Missing OAuth token for provider: google

Solutions:

  1. Set environment variables:
Terminal window
export GMAIL_ACCESS_TOKEN=ya29.your_token_here
export GITHUB_TOKEN=ghp_your_token_here
export SLACK_TOKEN=xoxb-your_token_here
  1. Verify token is set:
console.log(process.env.GMAIL_ACCESS_TOKEN);
// Should print your token, not undefined
  1. Check tool authentication config:
authentication:
type: oauth2
provider: google # Must match provider definition

Error: Provider definition not found: github

Solutions:

  1. Verify provider YAML exists:
Terminal window
ls tools/github/definition.yaml
# Should exist and contain: type: provider
  1. Check provider name:
Terminal window
pnpm validate-tools
# Lists all loaded providers
  1. Verify provider YAML format:
Terminal window
cat tools/github/definition.yaml | head -5
# Should show: type: provider

Error: Invalid authorization header

Solutions:

  1. Use correct token format:
Terminal window
# Correct: Just the token
export GMAIL_ACCESS_TOKEN=ya29.abc123
# Wrong: Don't include "Bearer"
export GMAIL_ACCESS_TOKEN="Bearer ya29.abc123"
  1. Verify token is actually a token:
Terminal window
echo $GMAIL_ACCESS_TOKEN | wc -c
# Should be > 20 characters

Error: Tool schema validation failed: • execution: Required

Solutions:

  1. Check required fields in tool YAML:
# All required fields
name: my-tool
version: 1.0.0
description: Tool description
parameters: {}
execution:
type: http
method: GET
url: https://api.example.com
  1. Run validation:
Terminal window
pnpm validate-tools
# Shows exact field errors

Error: Invalid execution type: webhook

Solutions: Supported execution types are:

  • command - Shell commands
  • http - HTTP requests

Unsupported (coming in future releases):

  • webhook - v0.3.0
  • grpc - Future
  • database - Future

Error: Tests pass in CI but fail locally

Solutions:

  1. Clear cache and reinstall:
Terminal window
pnpm clean
rm -rf node_modules pnpm-lock.yaml
pnpm install
  1. Run specific test:
Terminal window
pnpm test -- --testNamePattern="oauth2"
  1. Debug test:
Terminal window
node --inspect-brk ./node_modules/.bin/jest --runInBand
# Then open chrome://inspect

Error: ESLint errors found

Solution:

Terminal window
# Fix automatically
pnpm lint:fix
# Then format
pnpm format

Possible causes:

  1. Network latency (HTTP tools)
  2. OAuth token refresh overhead
  3. Tool parameter validation

Solutions:

// Time tool execution
console.time('tool-execution');
const result = await m.execute('gmail-send-email', params);
console.timeEnd('tool-execution');
// Optimize: Cache tools
const tool = m.getTool('gmail-send-email');
const result = await executor.execute(tool, params);

Solutions:

// Don't load all tools if not needed
const tools = m.listTools();
const filtered = tools.filter((t) => t.tags.includes('gmail'));
// Or use specific tool
const tool = m.getTool('gmail-send-email');

0.2.0 is secure by default. These are the errors you are most likely to meet after upgrading, and what to do. The full list of changes is in the migration guide.

Q: Destructive operation requires approval: <tool>

Section titled “Q: Destructive operation requires approval: <tool>”

The call needs a person’s approval and nothing can answer. In 0.2.0 that covers tools with requires_approval: true, HTTP DELETE and type: command tools that don’t set requires_approval, and calls whose sql/command argument contains a destructive keyword.

  • Give the instance a reviewer: MatimoInstance.init({ onApproval }) / Matimo.init(on_approval=...).
  • Or pre-approve tools that are safe in your setting: MATIMO_APPROVED_PATTERNS="get_*,list_*".
  • Or opt one tool out with requires_approval: false in its YAML, or restore the pre-0.2.0 default with governanceMode: 'legacy' while you migrate.

See Approval System.

Q: Operation rejected by approval handler: <tool>

Section titled “Q: Operation rejected by approval handler: <tool>”

Your onApproval callback returned false (or threw). That is the intended outcome of a decline.

Q: Draft tool "<name>" requires admin role / is not available in production

Section titled “Q: Draft tool "<name>" requires admin role / is not available in production”

The tool’s YAML has status: draft, every tool an agent creates starts that way. A draft never runs in production and runs elsewhere only for a caller whose PolicyContext has the admin role. Have a reviewer approve it with matimo_approve_tool (or the matimo review approve CLI), then reload the tools.

Q: An approved tool disappears on the next reload

Section titled “Q: An approved tool disappears on the next reload”

Check rejected in the reload result and the tool:rejected event. Common causes: the file changed after approval (the approval no longer matches), the tool breaks one of the developer’s policy rules (blocked-domain, blocked-http-method, unauthorized-credential), or the approval was made by another process without the same MATIMO_APPROVAL_SECRET and approvalDir.

Q: Tool '<name>' needs human approval, but this MCP client does not support elicitation

Section titled “Q: Tool '<name>' needs human approval, but this MCP client does not support elicitation”

Over MCP, Matimo asks the person behind the client through an elicitation request. Use a client that supports it, pre-approve the tool on the server with MATIMO_APPROVED_PATTERNS, or, only if the client confirms every call with its user, start the server with trustClientApproval: true. See MCP.

Q: A read-only SQL query asks for approval

Section titled “Q: A read-only SQL query asks for approval”

The keyword scan matches substrings of the upper-cased query, so a column like created_at contains CREATE. Approve it, or give read-only queries their own tool.

Q: Should I set MATIMO_AUTO_APPROVE=true in CI?

Section titled “Q: Should I set MATIMO_AUTO_APPROVE=true in CI?”

Prefer an onApproval that encodes what the test allows, or MATIMO_APPROVED_PATTERNS. MATIMO_AUTO_APPROVE approves everything unseen (except matimo_approve_tool) and logs a warning.


Error: Invalid input or schema validation error when invoking LangChain tool

Solutions:

  1. Check enum parameter handling:
// If tool has enum constraints, they're now properly validated
const tool = m.getTool('my-tool');
console.log(tool.parameters.status.enum); // Check allowed values
// Pass only allowed values
await langTool.invoke({ status: 'active' }); //
  1. Verify default values are set:
// Tools with default values should apply them automatically
await langTool.invoke({}); // Defaults injected
  1. Check secret parameter detection:
// Parameters with "token", "key", "secret", "password" are auto-hidden
// Only real secret patterns are filtered (not "monkey", "turkey_id", etc.)
const schema = langTool.schema;
console.log(Object.keys(schema.shape)); // Won't include api_key, but will include data

Error: Invalid option: expected one of "active"|"inactive"

Solutions:

  1. Verify parameter has enum defined:
parameters:
status:
type: string
enum: ['active', 'inactive', 'pending']
  1. Pass exact value:
// Correct
await m.execute('tool', { status: 'active' });
// Wrong
await m.execute('tool', { status: 'ACTIVE' }); // Case sensitive

Error: Tool requires parameter but default wasn’t used

Solutions:

  1. Mark parameter as optional if default provided:
parameters:
timeout:
type: number
required: false # Important!
default: 5000
  1. Verify default is valid type:
# Correct
default: 5000
# Wrong (must match type)
default: "5000" # for number type

Q: Function executor fails with “Cannot find module”

Section titled “Q: Function executor fails with “Cannot find module””

Error: Error: Cannot find module 'file:///path/to/tool.ts'

Solutions:

  1. Uses proper file URLs (Windows compatibility fixed):
// Now uses pathToFileURL() for robust URL construction
// Handles spaces, special chars, and Windows paths automatically
  1. Verify file exists:
Terminal window
ls -la tools/provider/tool-name/tool-name.ts
# Should exist and be readable
  1. Use relative paths in tool definition:
execution:
type: function
code: ./tool-name.ts # Relative to tool directory

Q: Parameter incorrectly treated as secret

Section titled “Q: Parameter incorrectly treated as secret”

Error: Parameter missing from LangChain schema (e.g., “monkey”, “turkey_id”)

Root Cause: Old substring matching was too loose

Solution: Now uses word-boundary matching:

// Old: Contains "key" substring → treated as secret
// "monkey", "turkey_id", "donkey" → incorrectly hidden
// New: Word-boundary matching
// "monkey" → NOT a secret ("key" is substring)
// "api_key" → IS a secret ("_key" is word boundary)
// "getSecret" → IS a secret ("Secret" is word boundary)

Verify parameter detection:

const langTools = await convertToolsToLangChain([tool], matimo, { api_key: 'secret' });
const schema = langTools[0].schema;
console.log(Object.keys(schema.shape));
// Should include: monkey, turkey_id, data
// Should exclude: api_key, real_secret

Still stuck? Try:

  1. GitHub Issues: Search issues
  2. GitHub Discussions: Ask questions
  3. Documentation: Full docs
  4. Examples: See examples

Found a bug? Help us fix it:

Terminal window
# 1. Check if issue exists
# Go to https://github.com/tallclub/matimo/issues
# 2. If not, create new issue with:
# - Matimo version: (run: npm list matimo)
# - Node.js version: (run: node --version)
# - Steps to reproduce
# - Expected vs actual behavior
# - Error message/stack trace

Thank you for helping improve Matimo!