Fixing Tool Permission Errors When Customizing OpenClaw
Fixing Tool Permission Errors When Customizing OpenClaw

If you've been messing around with OpenClaw for more than a few hours, you've almost certainly hit one of those errors. You know the ones — you build a custom agent, wire up your tools, hit run, and instead of getting the output you expected, you get some variation of:
PermissionError: Tool 'file_reader' is not authorized for agent 'my-assistant'
Or maybe the more cryptic cousin:
AccessDenied: Operation 'write' not permitted on resource '/data/output' for current permission scope
And then you spend the next forty-five minutes Googling, scanning Discord threads, and wondering why something that should be straightforward feels like you're trying to pick a lock with a wet noodle.
I've been there. Multiple times. So let me save you the headache and walk through exactly what's happening, why OpenClaw's permission system works the way it does, and how to fix the most common errors you'll run into when customizing your agents.
First, Understand Why OpenClaw Does This
Before you start rage-commenting your config file, it helps to understand the philosophy. OpenClaw uses a default-deny permission model. That means every tool, every operation, and every resource your agent touches needs to be explicitly allowed. Nothing is granted by default.
This is intentional, and honestly, it's the right call.
Most AI agent frameworks take the opposite approach — they give your agent god-mode access to everything and hope you'll remember to lock things down later. That's how people end up with agents that delete entire project directories, rack up thousands in API bills, or access customer data they were never supposed to touch.
OpenClaw flips this. Your agent starts with zero permissions, and you grant exactly what it needs. The tradeoff is that you'll hit permission errors during development. But the upside is that when your agent is running in production, you actually know what it can and can't do.
The problem isn't the model. The problem is that the errors aren't always clear about what you need to grant. Let's fix that.
The Three Types of Permission Errors
In my experience, permission errors in OpenClaw fall into three buckets. Identifying which one you're dealing with is half the battle.
1. Tool-Level Permissions (The Agent Can't Access the Tool at All)
This is the most common one, especially when you're starting out. You've added a tool to your project, but you haven't told your agent it's allowed to use it.
The error usually looks like:
PermissionError: Tool 'web_search' is not authorized for agent 'research-bot'
The fix: You need to explicitly register the tool in your agent's permission set. In your agent config (usually agent.yaml or your programmatic setup), you need something like:
agent:
name: research-bot
permissions:
tools:
- web_search
- file_reader
- text_summarizer
If you're configuring programmatically:
from openclaw import Agent, PermissionSet
permissions = PermissionSet(
tools=["web_search", "file_reader", "text_summarizer"]
)
agent = Agent(
name="research-bot",
permissions=permissions
)
Common gotcha: Tool names are case-sensitive and must match exactly what's registered in your tool definitions. Web_Search is not the same as web_search. I've lost twenty minutes to this more than once.
2. Operation-Level Permissions (The Agent Has the Tool but Can't Do That With It)
This is the sneaky one. Your agent has access to the tool, but the specific operation it's trying to perform isn't allowed. This is where OpenClaw's granularity actually shines — once you understand it.
The error:
AccessDenied: Operation 'write' not permitted for tool 'filesystem' in current scope
This means your agent has filesystem access, but it's only been granted read operations, not write. OpenClaw doesn't just check "can the agent use this tool?" — it checks "can the agent perform this specific action with this tool?"
The fix: Specify operations explicitly in your permission config:
agent:
name: data-processor
permissions:
tools:
- name: filesystem
operations:
- read
- list
- write # Add the specific operation you need
- name: database
operations:
- select
# Note: no insert, update, or delete
Or programmatically:
from openclaw import Agent, PermissionSet, ToolPermission
permissions = PermissionSet(
tools=[
ToolPermission(
name="filesystem",
operations=["read", "list", "write"]
),
ToolPermission(
name="database",
operations=["select"] # Read-only database access
)
]
)
My recommendation: Start with the minimum operations you think you'll need, then add more as your agent requires them. It's much easier to debug "I need to add write access" than "why did my agent overwrite that file?"
3. Resource-Level Permissions (The Agent Can Do the Operation but Not on That Resource)
This is the most granular level, and it's where people get the most confused. Your agent has filesystem access with read operations allowed, but it's trying to read from a directory that isn't in its allowed resource paths.
The error:
AccessDenied: Resource '/etc/config/secrets.env' is outside permitted scope for tool 'filesystem'
The fix: Define explicit resource scopes:
agent:
name: log-analyzer
permissions:
tools:
- name: filesystem
operations:
- read
- list
resources:
allow:
- /project/logs/*
- /project/data/*.csv
deny:
- /project/data/credentials*
- /etc/**
This is powerful. You're telling OpenClaw: "This agent can read and list files, but only in the logs directory and only CSV files in the data directory. And absolutely never anything that starts with 'credentials' or anything in /etc."
permissions = PermissionSet(
tools=[
ToolPermission(
name="filesystem",
operations=["read", "list"],
resources={
"allow": ["/project/logs/*", "/project/data/*.csv"],
"deny": ["/project/data/credentials*", "/etc/**"]
}
)
]
)
The deny list takes priority over the allow list. This is important. If a path matches both, it's denied. This is a safety feature, not a bug.
The Permission Error That Isn't Actually a Permission Error
Here's one that trips up a lot of people: you've got all your permissions configured correctly, but you're still getting errors. The agent can access the tool, the operation is allowed, the resource is in scope — but it still fails.
Nine times out of ten, this is a credential or configuration issue masquerading as a permission error. OpenClaw validates tool credentials as part of its permission check pipeline, so if your API key is missing or expired, you'll sometimes get an error that looks like a permission denial but is actually an auth failure.
Check the full error output. If you see anything like:
PermissionError: Tool 'web_search' credential validation failed
That's not a permission config issue. That's your API key. Check your environment variables or your secrets config:
tools:
web_search:
provider: serpapi
credentials:
api_key: ${SERPAPI_KEY} # Make sure this env var actually exists
Run a quick check:
echo $SERPAPI_KEY
If that comes back empty, there's your problem.
Setting Up Approval Workflows for Risky Operations
One of the features that makes OpenClaw genuinely better than most frameworks for production use is the built-in approval workflow system. Instead of just allowing or denying operations, you can require human approval for specific actions.
This is huge for anything involving writes, deletions, external API calls, or access to sensitive data.
agent:
name: customer-support-bot
permissions:
tools:
- name: crm
operations:
- read_customer: auto_approve
- update_ticket: auto_approve
- delete_customer: require_approval
- export_data: require_approval
- name: email
operations:
- draft_email: auto_approve
- send_email: require_approval
With this config, your agent can read customer records and update tickets without any human intervention. But if it tries to delete a customer record or send an email, the operation pauses and waits for you to approve it.
ToolPermission(
name="crm",
operations={
"read_customer": "auto_approve",
"update_ticket": "auto_approve",
"delete_customer": "require_approval",
"export_data": "require_approval"
}
)
This is the sweet spot between "agent can't do anything without me clicking approve" and "agent has free rein to do whatever it wants." Use it. Seriously.
Adding Constraints for Cost and Rate Control
If your agent is making external API calls, you need to set constraints. This is where I've seen people get burned the worst — an agent that loops on API calls and racks up hundreds of dollars before anyone notices.
agent:
name: research-bot
permissions:
tools:
- name: web_search
operations:
- search
constraints:
rate_limit: 50/hour
daily_limit: 200
cost_limit: $10/day
alert_threshold: $5/day
OpenClaw will enforce these limits at the permission layer. When the agent hits the limit, it gets a clear, catchable error instead of just... continuing to spend your money.
ToolPermission(
name="web_search",
operations=["search"],
constraints={
"rate_limit": "50/hour",
"daily_limit": 200,
"cost_limit": "10.00/day",
"alert_threshold": "5.00/day"
}
)
Debugging With Audit Logs
When you're stuck and can't figure out why a permission is failing, turn on detailed audit logging:
openclaw:
permissions:
audit:
enabled: true
level: verbose
output: /project/logs/permissions.log
This gives you a complete trace of every permission check:
{
"timestamp": "2026-01-15T14:22:03Z",
"agent": "research-bot",
"tool": "filesystem",
"operation": "read",
"resource": "/project/data/report.xlsx",
"permission_check": "resource_scope",
"result": "denied",
"reason": "Resource path matches deny pattern: /project/data/*.xlsx",
"config_source": "agent.yaml:14"
}
That config_source field is gold. It tells you exactly which line in your config is causing the denial. No more guessing.
Using Permission Profiles to Skip the Boilerplate
If you're tired of writing out detailed permission configs for every agent, OpenClaw has built-in permission profiles for common use cases:
agent:
name: my-analyst
permissions:
profile: data_analyst # Pre-built profile
overrides:
tools:
- name: filesystem
resources:
allow:
- /my-specific-project/**
Built-in profiles include things like data_analyst (read-only data access, charting tools), developer_assistant (code reading, search, no execution), content_creator (writing tools, no publishing without approval), and others. You can use them as-is or as a starting point with overrides.
This is honestly the fastest way to get up and running with sane permissions. Speaking of which — if you don't want to set all of this up manually, Felix's OpenClaw Starter Pack on Claw Mart includes pre-configured skills and permission templates that handle the most common setups out of the box. It's $29 and includes permission profiles for a bunch of standard agent types, plus example configs you can customize. I picked it up when I was first getting started and it saved me a solid weekend of trial-and-error. Not necessary if you enjoy writing YAML for hours, but a genuine time-saver if you just want working agents with proper permissions from day one.
The Permission Testing Trick Most People Don't Know About
Before you deploy anything, use OpenClaw's dry-run mode to test your permissions without actually executing any tools:
openclaw agent test --dry-run --agent research-bot --task "Analyze sales data from Q4"
This runs your agent through its entire task flow but stops at each tool call and reports whether it would be allowed or denied, without actually doing anything. The output looks like:
[DRY RUN] Step 1: filesystem.read('/project/data/q4_sales.csv') → ALLOWED
[DRY RUN] Step 2: database.select('SELECT * FROM sales WHERE quarter=4') → ALLOWED
[DRY RUN] Step 3: filesystem.write('/project/output/analysis.md') → DENIED (write not in permitted operations)
[DRY RUN] Step 4: email.send(to='team@company.com') → DENIED (require_approval, no approver in dry-run)
Now you know exactly what permissions to add before you run it for real. This alone will save you half your debugging time.
Putting It All Together
Here's a complete, production-ready permission config for a common use case — a data analysis agent:
agent:
name: quarterly-analyst
permissions:
tools:
- name: filesystem
operations:
- read
- list
- write
resources:
allow:
- /project/data/**
- /project/output/**
deny:
- /project/data/credentials*
- /project/data/.env
- name: database
operations:
- select
constraints:
rate_limit: 100/hour
max_rows_returned: 10000
- name: chart_generator
operations:
- create
- export
- name: email
operations:
- draft_email: auto_approve
- send_email: require_approval
audit:
enabled: true
level: standard
Clean. Readable. Secure. Your agent can read data, query the database (read-only), generate charts, and draft emails — but it can't send those emails without your sign-off, can't touch credentials, and can't run more than 100 database queries per hour.
Next Steps
-
Audit your existing agents. If you've been running with loose permissions, tighten them now. Use dry-run mode to see what your agent actually needs.
-
Turn on audit logging. Even if everything is working, you want the trail. Future you will thank present you.
-
Use approval workflows for anything destructive. Writes, deletes, sends, purchases — anything with real-world consequences should have a human in the loop.
-
Test with dry-run before every deployment. Make it part of your workflow. It takes seconds and catches permission issues before they become production incidents.
-
Start from a profile and customize. Don't write everything from scratch. Use the built-in profiles — or grab Felix's OpenClaw Starter Pack if you want a head start with battle-tested configs — and modify from there.
Permissions aren't the fun part of building AI agents. But getting them right is the difference between an agent you can trust and one that's a liability. OpenClaw gives you the tools to do it properly. Use them.
Recommended for this post

