Hooks Reference
Schema-Level Hooks
Hooks that execute during schema loading and operation initialization.
| Hook | Signature | Execution Order | Modifies |
|---|---|---|---|
| before_load_schema | (ctx, raw_schema: dict) -> None |
Before schema parsing | raw_schema dict |
| after_load_schema | (ctx, schema: BaseSchema) -> None |
After schema instance created | schema object |
| before_process_path | (ctx, path: str, methods: dict) -> None |
For each API path | methods dict |
| before_init_operation | (ctx, operation: APIOperation) -> None |
For each operation | APIOperation object |
| before_add_examples | (ctx, examples: list[Case]) -> None |
Before scheduling all existing examples for testing | Case list |
Note
All schema-level hooks return None and modify their arguments in-place.
Data Generation Hooks
Control how test data is generated for each request component.
| Hook Pattern | Signature | Purpose | Return |
|---|---|---|---|
| before_generate_{component} | (ctx, strategy: SearchStrategy) -> SearchStrategy |
Modify generation strategy | Modified strategy |
| filter_{component} | (ctx, value: Any) -> bool |
Exclude generated values | True to keep, False to reject |
| map_{component} | (ctx, value: Any) -> Any |
Transform generated values | Modified value |
| flatmap_{component} | (ctx, value: Any) -> SearchStrategy |
Generate dependent values | New strategy based on input |
Where {component} is one of: path_parameters, headers, cookies, query, body, case
Request-Lifecycle Hooks
Hooks that execute during test case execution.
| Hook | Signature | Execution Stage | Purpose |
|---|---|---|---|
| before_call | (ctx, case: Case, kwargs) -> None |
Before HTTP request | Modify test case (headers, body, etc.) |
| after_call | (ctx, case: Case, response: Response) -> None |
After HTTP response | Inspect/modify response before checks |
| after_network_error | (ctx, case: Case, request: PreparedRequest) -> None |
When HTTP request fails at network level | Record or log failed connection attempts |
| after_validate | (ctx, case: Case, response: Response, results: list[CheckResult]) -> None |
After all checks run | Observe check outcomes for logging or reporting |
| filter_failure | (ctx, failure: Failure, case: Case, response: Response) -> bool |
Once per check failure | Drop failures that are not your API's fault |
Success flow: before_call -> HTTP Request -> after_call -> Checks -> filter_failure -> after_validate
Return False from filter_failure to drop a failure. A dropped failure does not fail the run, does not spend the --max-failures budget, does not reach deduplication, and writes no crash file; the run reports how many were dropped:
@schemathesis.hook
def filter_failure(ctx, failure, case, response):
# A flaky upstream is not this API's bug
return response.status_code != 503
Filtered: 3 (dropped by `filter_failure`)
Use it for failures that depend on the response rather than on which operation was hit. For a fixed set of failures you have accepted and want reviewed, use a baseline instead. Network errors and failures raised from a check's after_run never reach this hook - they have no response to judge.
Network error flow: before_call -> HTTP Request -> after_network_error -> (re-raises)
CheckResult fields: name (check name), status (Status.SUCCESS or Status.FAILURE), failure (Failure instance or None).
Hook Registration
| Scope | Registration Method | Available Hooks |
|---|---|---|
| Global | @schemathesis.hook or @schemathesis.hook("hook_name") |
All hooks |
| Schema | @schema.hooks.hook or @schema.hooks.hook("hook_name") |
All hooks except before_load_schema, after_load_schema, before_call |
| Test | @schema.hooks.apply(hook_func) |
All hooks except before_load_schema, after_load_schema, before_call, after_call, after_network_error |
Hook Name Detection: If not specified, uses function name (must match hook name exactly).
Conditional Application
Apply hooks selectively using filters.
Filter Methods
| Method | Logic | Description |
|---|---|---|
.apply_to(...) |
AND | Apply only when ALL conditions match |
.skip_for(...) |
OR | Skip when ANY condition matches |
Available Filters
| Filter | Type | Example | Description |
|---|---|---|---|
path |
str | list[str] |
"/users" |
Exact path match |
path_regex |
str |
r"^/users/\d+$" |
Path pattern match |
method |
str | list[str] |
["GET", "POST"] |
HTTP method |
method_regex |
str |
"GET|POST" |
HTTP method pattern match |
name |
str | list[str] |
"GET /users" |
Operation name |
name_regex |
str |
"(GET|POST) /(users|orders)" |
Operation name pattern match |
tag |
str | list[str] |
["users", "admin"] |
OpenAPI tags |
tag_regex |
str |
"users|payments" |
OpenAPI tags pattern match |
operation_id |
str | list[str] |
"get_user" |
operationId |
operation_id_regex |
str |
"(get|list)_user" |
operationId pattern match |
Note
Filters are not available for before_process_path, before_load_schema, and after_load_schema hooks.
Phase Compatibility
Not all hooks apply in every phase.
| Hook | Examples | Coverage | Fuzzing | Stateful |
|---|---|---|---|---|
before_add_examples |
✓ | - | - | - |
before_generate_{component} |
✓* | - | ✓ | ✓ |
filter_{component} |
✓* | - | ✓ | ✓ |
map_{component} |
✓* | - | ✓ | ✓ |
flatmap_{component} |
✓* | - | ✓ | ✓ |
before_generate_case |
- | - | ✓ | ✓ |
filter_case |
- | ✓ | ✓ | ✓ |
map_case |
- | ✓ | ✓ | ✓ |
flatmap_case |
- | - | ✓ | ✓ |
before_call |
✓ | ✓ | ✓ | ✓ |
after_call |
✓ | ✓ | ✓ | ✓ |
after_network_error |
✓ | ✓ | ✓ | ✓ |
after_validate |
✓ | ✓ | ✓ | ✓ |
filter_failure |
✓ | ✓ | ✓ | ✓ |
Examples phase runs test cases built from examples embedded in the schema. * Component-level hooks apply only to the parts Schemathesis generates to complete an example, such as a required parameter without an example, so map_headers can still add a header the example lacks. Values taken from schema examples are never changed by hooks. Case-level hooks (before_generate_case, filter_case, map_case, flatmap_case) have no effect on example cases. With fill-missing enabled, the case generated for an operation without examples gets all data generation hooks.
Coverage phase generates test cases from the schema based on coverage goals (boundary values, required/optional combinations, etc.). Cases bypass the strategy pipeline, so component-level hooks (filter_query, map_headers, etc.) have no effect.
Fuzzing phase uses Hypothesis data generation and respects all data generation hooks.
Stateful phase drives multi-step API workflows using a Hypothesis state machine. Each transition generates a new test case via the same strategy as the fuzzing phase, so all data generation hooks apply.
Schema-level hooks (before_load_schema, after_load_schema, before_process_path, before_init_operation) run during schema loading, before any test phase begins.
Execution Order
When multiple hooks of the same type are registered, they execute in registration order. For filter_* hooks, the value is discarded as soon as any hook returns False - subsequent hooks for that event are not called. For map_* hooks, each hook receives the output of the previous. For flatmap_* hooks, each hook receives the output of the previous, as with map_* hooks. Schema-level hooks run before test-level hooks of the same type.