Cause: The tool name passed to enforce_sync() / enforce_async()
contains characters outside the allowed set.
Allowed characters: Word characters (a-z, A-Z, 0-9, _),
dots (.), hyphens (-), colons (:), and angle brackets (<, >).
Fix: Pass a valid tool_name explicitly:
enforcer.enforce_sync(my_func, arg, tool_name="my_tool")Or rename your function to use valid characters.
Cause: The combined size of all string and bytes arguments exceeds 10 MB (default).
Fix: Reduce input size, or if you need to process large payloads,
use check_input_size() with a higher max_bytes:
from enforcecore import check_input_size
check_input_size(args, kwargs, max_bytes=50 * 1024 * 1024) # 50 MBNote: The default 10 MB limit applies automatically in enforce_sync()
and enforce_async(). To change it globally, modify the constant
MAX_INPUT_SIZE_BYTES or subclass Enforcer.
Cause: An enforced tool called another enforced tool, and the nesting exceeded the maximum depth (default: 10).
Fix: Check for recursive enforcement chains. The error message includes the call chain for debugging:
Call chain: tool_a -> tool_b -> tool_c -> ... -> tool_a
If legitimate deep nesting is needed, increase the max_depth parameter:
from enforcecore import enter_enforcement
enter_enforcement("my_tool", max_depth=20)Cause: The policy does not allow the tool being called.
Fix: Add the tool name to allowed_tools in your policy YAML:
rules:
allowed_tools:
- "search_web"
- "your_tool_name" # Add thisOr remove denied_tools restrictions if they apply.
Cause: The total cost recorded via enforcer.record_cost() exceeded
the budget configured in resource_limits.max_cost_usd or the global
ENFORCECORE_COST_BUDGET_USD.
Fix: Increase the budget, or reset the cost tracker:
enforcer.guard.cost_tracker.reset()Cause: A tool call exceeded the time limit configured in the policy's
resource_limits.max_call_duration_seconds.
Fix: Increase the time limit in your policy:
rules:
resource_limits:
max_call_duration_seconds: 60 # Increase from defaultOr optimize the tool to run faster.
Cause: fail_open=True is set in the configuration, but the
ENFORCECORE_DEV_MODE environment variable is not set.
Fix: Either:
-
Disable fail_open (recommended for production):
ENFORCECORE_FAIL_OPEN=false
-
Acknowledge dev mode (development only):
ENFORCECORE_DEV_MODE=1
Cause: guard_sync() and guard_async() were removed in v1.0.16.
They only performed pre-call checks without redaction, audit, or resource
guards.
Fix: Use enforce_sync() / enforce_async() for full protection:
# Instead of this (removed):
# with enforcer.guard_sync("my_tool") as ctx:
# result = do_something()
# Do this:
result = enforcer.enforce_sync(do_something, tool_name="my_tool")See docs/migration.md for the full migration guide.
Cause: @enforce was used without arguments and no default policy
is configured.
Fix: Either pass a policy explicitly:
@enforce(policy="policy.yaml")
def my_tool(): ...Or set a default policy:
ENFORCECORE_DEFAULT_POLICY=policies/default.yamlCause: An unrecognized PII category was passed to the Redactor.
Supported categories: email, phone, ssn, credit_card,
ip_address, person_name.
Fix: Use one of the supported categories:
redactor = Redactor(categories=["email", "phone"])ENFORCECORE_LOG_LEVEL=DEBUGThis shows detailed structured logs for every enforcement decision, redaction event, and audit entry.
from enforcecore import get_enforcement_depth, get_enforcement_chain
print(f"Depth: {get_enforcement_depth()}")
print(f"Chain: {get_enforcement_chain()}")from enforcecore import verify_trail
result = verify_trail("audit.jsonl")
if not result.is_valid:
for error in result.errors:
print(f" ERROR: {error}")from enforcecore.eval import ScenarioRunner
from enforcecore.core.policy import Policy
policy = Policy.from_file("policy.yaml")
runner = ScenarioRunner(policy)
suite = runner.run_all()
print(f"Containment rate: {suite.containment_rate:.0%}")Memory limits use RLIMIT_RSS which is advisory (not strictly enforced
by the kernel). Time limits and cost tracking work fully.
Memory limits are not available. Time limits, cost tracking, and all other features work fully.
Full support for all features including strict memory limits via
RLIMIT_AS.