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.
Installation & Setup
Section titled “Installation & Setup”TypeScript Issues
Section titled “TypeScript Issues”Q: Node.js version error
Section titled “Q: Node.js version error”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:
node --version# If below v22.19, install from https://nodejs.org# Use nvm (Node Version Manager) for easy switching:nvm install 22nvm use 22Q: pnpm not found
Section titled “Q: pnpm not found”Error: pnpm: command not found
Solution:
npm install -g pnpm@8.15.0pnpm --versionQ: Build fails with TypeScript errors
Section titled “Q: Build fails with TypeScript errors”Error: Found X errors in src/**
Solution:
# Clear and rebuildpnpm cleanpnpm installpnpm build
# If still failing, check TypeScript versionpnpm list typescript# Should be 5.9.3 or higherPython Issues
Section titled “Python Issues”Q: Python version too old
Section titled “Q: Python version too old”Error: ModuleNotFoundError: No module named 'matimo' or Python 3.10 or lower detected
Solution:
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 environmentpython3.11 -m venv venvsource venv/bin/activate # or 'venv\Scripts\activate' on WindowsQ: pip install matimo fails
Section titled “Q: pip install matimo fails”Error: ERROR: Could not find a version that satisfies the requirement
Solution:
# 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 pippip install matimo
# For specific version:pip install matimo==0.2.0Q: LangChain or CrewAI imports fail
Section titled “Q: LangChain or CrewAI imports fail”Error: ModuleNotFoundError: No module named 'langchain' / ModuleNotFoundError: No module named 'crewai'
Solution:
# Install with extras:pip install "matimo-core[langchain]"#orpip 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')"Q: Async/await RuntimeError in Jupyter
Section titled “Q: Async/await RuntimeError in Jupyter”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:
pip install nest_asyncioimport nest_asyncionest_asyncio.apply()Q: CrewAI tools not executing
Section titled “Q: CrewAI tools not executing”Error: Tool execution timeout or Tool not callable
Solution:
# Verify tools are created correctlytools = 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 workSecurity & Embedded Code
Section titled “Security & Embedded Code”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:
- Recommended: Use external TypeScript files instead:
# Secure: External fileexecution: type: function code: ./handler.ts # Version-controlled, auditable timeout: 10000- If you must use embedded code (NOT recommended):
# Only in trusted environmentsexport MATIMO_ALLOW_EMBEDDED_CODE=true
# Then run your toolpnpm agent:factoryQ: 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:
fsmodule (file system read/write)pathmodule (path manipulation)axiosmodule (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
Tool Execution
Section titled “Tool Execution”Q: Tool not found error
Section titled “Q: Tool not found error”Error: Tool not found: calculator
Solutions:
- Verify tool exists:
pnpm validate-tools# Lists all loaded tools- Check tools directory:
# Ensure tools/calculator/definition.yaml existsls -la tools/calculator/definition.yaml- Verify tool definition:
pnpm validate-tools# Shows validation errors if YAML is invalidQ: Invalid parameters error
Section titled “Q: Invalid parameters error”Error: Tool validation failed: Missing required parameter: operation
Solutions:
- Check tool parameters:
const tool = matimoInstance.getTool('calculator');console.log(tool.parameters); // See required fields- Verify your input matches schema:
// Wrongawait m.execute('calculator', { value: 5 });
// Correctawait m.execute('calculator', { operation: 'add', a: 5, b: 3,});- Check tool spec:
cat tools/calculator/definition.yaml | grep -A 20 "parameters:"Q: HTTP tool returns 401 Unauthorized
Section titled “Q: HTTP tool returns 401 Unauthorized”Error: HTTP 401: Unauthorized
Common causes:
- Missing OAuth token:
# Set required tokensexport GMAIL_ACCESS_TOKEN=your_tokenexport GITHUB_TOKEN=your_token- Expired token:
// Token needs refreshconst newToken = await oauth2Handler.refreshTokenIfNeeded(userId, currentToken);- 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..."Q: Command executor fails
Section titled “Q: Command executor fails”Error: Command not found: node or shell command fails
Solutions:
- Verify command exists:
which nodewhich python- Check working directory:
execution: type: command command: ./script.sh cwd: /path/to/directory # Ensure this exists- Test command manually:
# Test the exact commandnode calculator.js --op add 5 3OAuth2 & Authentication
Section titled “OAuth2 & Authentication”Q: OAuth token missing error
Section titled “Q: OAuth token missing error”Error: Missing OAuth token for provider: google
Solutions:
- Set environment variables:
export GMAIL_ACCESS_TOKEN=ya29.your_token_hereexport GITHUB_TOKEN=ghp_your_token_hereexport SLACK_TOKEN=xoxb-your_token_here- Verify token is set:
console.log(process.env.GMAIL_ACCESS_TOKEN);// Should print your token, not undefined- Check tool authentication config:
authentication: type: oauth2 provider: google # Must match provider definitionQ: OAuth provider configuration not found
Section titled “Q: OAuth provider configuration not found”Error: Provider definition not found: github
Solutions:
- Verify provider YAML exists:
ls tools/github/definition.yaml# Should exist and contain: type: provider- Check provider name:
pnpm validate-tools# Lists all loaded providers- Verify provider YAML format:
cat tools/github/definition.yaml | head -5# Should show: type: providerQ: Bearer token format issue
Section titled “Q: Bearer token format issue”Error: Invalid authorization header
Solutions:
- Use correct token format:
# Correct: Just the tokenexport GMAIL_ACCESS_TOKEN=ya29.abc123
# Wrong: Don't include "Bearer"export GMAIL_ACCESS_TOKEN="Bearer ya29.abc123"- Verify token is actually a token:
echo $GMAIL_ACCESS_TOKEN | wc -c# Should be > 20 charactersValidation Errors
Section titled “Validation Errors”Q: Schema validation failed
Section titled “Q: Schema validation failed”Error: Tool schema validation failed: • execution: Required
Solutions:
- Check required fields in tool YAML:
# All required fieldsname: my-toolversion: 1.0.0description: Tool descriptionparameters: {}execution: type: http method: GET url: https://api.example.com- Run validation:
pnpm validate-tools# Shows exact field errorsQ: Invalid execution type
Section titled “Q: Invalid execution type”Error: Invalid execution type: webhook
Solutions: Supported execution types are:
command- Shell commandshttp- HTTP requests
Unsupported (coming in future releases):
webhook- v0.3.0grpc- Futuredatabase- Future
Testing & Development
Section titled “Testing & Development”Q: Tests fail locally
Section titled “Q: Tests fail locally”Error: Tests pass in CI but fail locally
Solutions:
- Clear cache and reinstall:
pnpm cleanrm -rf node_modules pnpm-lock.yamlpnpm install- Run specific test:
pnpm test -- --testNamePattern="oauth2"- Debug test:
node --inspect-brk ./node_modules/.bin/jest --runInBand# Then open chrome://inspectQ: Linting errors
Section titled “Q: Linting errors”Error: ESLint errors found
Solution:
# Fix automaticallypnpm lint:fix
# Then formatpnpm formatPerformance Issues
Section titled “Performance Issues”Q: Tool execution is slow
Section titled “Q: Tool execution is slow”Possible causes:
- Network latency (HTTP tools)
- OAuth token refresh overhead
- Tool parameter validation
Solutions:
// Time tool executionconsole.time('tool-execution');const result = await m.execute('gmail-send-email', params);console.timeEnd('tool-execution');
// Optimize: Cache toolsconst tool = m.getTool('gmail-send-email');const result = await executor.execute(tool, params);Q: High memory usage
Section titled “Q: High memory usage”Solutions:
// Don't load all tools if not neededconst tools = m.listTools();const filtered = tools.filter((t) => t.tags.includes('gmail'));
// Or use specific toolconst tool = m.getTool('gmail-send-email');Governance in 0.2.0
Section titled “Governance in 0.2.0”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: falsein its YAML, or restore the pre-0.2.0 default withgovernanceMode: '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.
LangChain Integration Issues
Section titled “LangChain Integration Issues”Q: LangChain tool schema validation fails
Section titled “Q: LangChain tool schema validation fails”Error: Invalid input or schema validation error when invoking LangChain tool
Solutions:
- Check enum parameter handling:
// If tool has enum constraints, they're now properly validatedconst tool = m.getTool('my-tool');console.log(tool.parameters.status.enum); // Check allowed values
// Pass only allowed valuesawait langTool.invoke({ status: 'active' }); //- Verify default values are set:
// Tools with default values should apply them automaticallyawait langTool.invoke({}); // Defaults injected- 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 dataParameter Validation Issues
Section titled “Parameter Validation Issues”Q: Enum parameter rejected valid value
Section titled “Q: Enum parameter rejected valid value”Error: Invalid option: expected one of "active"|"inactive"
Solutions:
- Verify parameter has enum defined:
parameters: status: type: string enum: ['active', 'inactive', 'pending']- Pass exact value:
// Correctawait m.execute('tool', { status: 'active' });
// Wrongawait m.execute('tool', { status: 'ACTIVE' }); // Case sensitiveQ: Default value not applied
Section titled “Q: Default value not applied”Error: Tool requires parameter but default wasn’t used
Solutions:
- Mark parameter as optional if default provided:
parameters: timeout: type: number required: false # Important! default: 5000- Verify default is valid type:
# Correctdefault: 5000
# Wrong (must match type)default: "5000" # for number typeFile Path & URL Issues
Section titled “File Path & URL Issues”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:
- Uses proper file URLs (Windows compatibility fixed):
// Now uses pathToFileURL() for robust URL construction// Handles spaces, special chars, and Windows paths automatically- Verify file exists:
ls -la tools/provider/tool-name/tool-name.ts# Should exist and be readable- Use relative paths in tool definition:
execution: type: function code: ./tool-name.ts # Relative to tool directorySecret Detection Issues
Section titled “Secret Detection Issues”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_secretStill stuck? Try:
- GitHub Issues: Search issues
- GitHub Discussions: Ask questions
- Documentation: Full docs
- Examples: See examples
Report a Bug
Section titled “Report a Bug”Found a bug? Help us fix it:
# 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 traceThank you for helping improve Matimo!