unclecode/crawl4ai · error · HookValidationError
invalid params for hook '{action}': {e}
Error message
invalid params for hook '{action}': {e} What it means
build_declarative_hooks wraps pydantic validation of each spec's params: if entry['params_model'](**raw_params) raises (missing required field, out-of-range value, unknown field, or one of the field_validator errors like bad resource types or header checks), it re-raises as HookValidationError("invalid params for hook '<action>': <pydantic message>"). The inner message identifies the exact field problem.
Source
Thrown at deploy/docker/hook_registry.py:219
"""
if not specs:
return {}
if len(specs) > 10:
raise HookValidationError("too many hooks (max 10)")
grouped: Dict[str, List[Callable]] = {}
for spec in specs:
action = spec.get("action") if isinstance(spec, dict) else getattr(spec, "action", None)
raw_params = (spec.get("params", {}) if isinstance(spec, dict) else getattr(spec, "params", {})) or {}
entry = HOOK_REGISTRY.get(action)
if entry is None:
raise HookValidationError(
f"unknown hook action {action!r}; allowed: {sorted(HOOK_REGISTRY)}"
)
try:
params = entry["params_model"](**raw_params)
except Exception as e:
raise HookValidationError(f"invalid params for hook '{action}': {e}")
sub_hook = entry["factory"](params)
grouped.setdefault(entry["hook_point"], []).append(sub_hook)
hooks: Dict[str, Callable] = {}
for hook_point, sub_hooks in grouped.items():
def _compose(sub_hooks):
async def composed(page, **kwargs):
for fn in sub_hooks:
await fn(page, **kwargs)
return page
return composed
hooks[hook_point] = _compose(sub_hooks)
return hooks
def describe_registry() -> dict:
"""Enumerate the available declarative actions for /hooks/info."""
return {View on GitHub (pinned to 7e80152142)
Solutions
- Parse the pydantic detail after the colon — it names the field and the constraint (e.g. 'timeout_ms: Input should be at most ...').
- Re-check the params schema for that action in hook_registry.py (the *_Params model) and conform the spec.
- Validate specs client-side with the same constraints before submitting the crawl job.
Example fix
# before
{"action": "wait_for_timeout", "params": {"timeout_ms": 999999999}}
# after
{"action": "wait_for_timeout", "params": {"timeout_ms": 5000}} Defensive patterns
Strategy: try-catch
Validate before calling
from hook_registry import HOOK_REGISTRY
def validate_spec(spec: dict):
entry = HOOK_REGISTRY.get(spec.get("action"))
if entry is None:
raise ValueError(f"unknown action {spec.get('action')!r}")
return entry["params_model"](**(spec.get("params") or {})) # raises early with field detail Type guard
def has_required_params(spec: dict) -> bool:
entry = HOOK_REGISTRY.get(spec.get("action"))
if not entry:
return False
required = entry["params_model"].model_fields
params = spec.get("params") or {}
return all(k in params for k, f in required.items() if f.is_required()) Try / catch
from hook_registry import build_declarative_hooks, HookValidationError
try:
hooks = build_declarative_hooks(specs)
except HookValidationError as e:
# inner pydantic text after ': ' names the field and constraint
field_err = str(e).split(": ", 1)[-1]
report_config_error(specs, field_err) Prevention
- Mirror each *_Params model's constraints (ge/le bounds, required fields) in the client schema.
- Dry-run build_declarative_hooks on config load, not at crawl time.
- Fuzz boundary values (0, max, max+1) in config tests.
When it happens
Trigger: Omitting a required field (e.g. block_resources without resource_types); out-of-range numbers (wait_for_timeout timeout_ms > _MAX_WAIT_MS, scroll_to_bottom delay_ms > _MAX_SCROLL_DELAY_MS); wrong types (string where int expected); passing fields the params model does not define.
Common situations: Hand-written JSON configs with typos or missing keys; defaults assumed from a different version; unit or boundary values exceeding the declared ge/le bounds.
Related errors
- unsupported resource_types {bad}; allowed: {sorted(_ALLOWED_
- too many headers (max {_MAX_HEADERS})
- too many hooks (max 10)
- unknown hook action {action!r}; allowed: {sorted(HOOK_REGIST
- str(e)
AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14).
Data as JSON: /api/errors/265423dcfc88c7f1.
Report an issue: GitHub.