Component
API Server / GraphQL
Infrahub version
1.10.0
Current Behavior
Webhook automations fail at Prefect parameter-render time when an event fires, so the webhook-process deployment is never run and no HTTP request is sent. The failure happens inside Prefect's action parameter hydration, before any Infrahub webhook code executes.
WebhookTriggerDefinitionBuilder.build() (backend/infrahub/webhook/models.py) emits several action parameters as bare single-expression Jinja strings:
"branch_name": "{{ event.resource['infrahub.branch.name'] }}",
"event_id": "{{ event.id }}",
"event_type": "{{ event.event }}",
"event_occured_at": "{{ event.occurred }}",
When the automation fires, Prefect's RunDeployment.render_parameters() runs _upgrade_v1_templates(), which auto-rewrites every bare {{ … }} parameter into {{ … | tojson }} (to preserve value types through a JSON round-trip). tojson then calls json.dumps() on values that are not JSON-native:
event_id → event.id is a UUID → TypeError: Object of type UUID is not JSON serializable — crashes on every webhook fire
event_occured_at → event.occurred is a datetime → TypeError: Object of type datetime is not JSON serializable — crashes on every webhook fire
branch_name → resolves to ChainableUndefined whenever the firing event's resource has no infrahub.branch.name key (e.g. account/login events) → TypeError
The error surfaces from Prefect as:
prefect.utilities.schema_tools.hydration.InvalidJinja: Invalid jinja: Failed to render
template due to the following error: TypeError('Object of type UUID is not JSON serializable')
Note: the event_payload parameter ({{ event.payload | tojson }}) is correctly wrapped in a json+jinja structure and is not the cause — it renders fine.
Why custom webhooks are the most visible: standard and custom webhooks share WebhookTriggerDefinitionBuilder, so event_id/event_occured_at break both. Custom webhooks additionally default to event_type="all" (→ listen on infrahub.*), so they also receive events lacking infrahub.branch.name and hit the branch_name crash branch too.
Expected Behavior
Webhook automations render their parameters successfully for any triggering event and dispatch the configured HTTP request. Scalar parameters (event_id, event_occured_at, branch_name) should be delivered as strings; events without a branch resource should yield an empty/absent branch rather than crashing.
Steps to Reproduce
- Create a Custom Webhook pointing at any reachable URL, leaving
event_type at its default (all).
- Trigger any Infrahub event (e.g. create/update a node, or any account/login event).
- Observe the
webhook-process automation fail on Prefect during parameter rendering — no HTTP request reaches the target URL.
Minimal mechanism reproduction (mirrors RunDeployment.render_parameters):
import copy
from prefect.server.events.actions import RunDeployment
from prefect.utilities.schema_tools.hydration import hydrate, HydrationContext
params = {"event_id": "{{ event.id }}"} # as emitted by the webhook builder
RunDeployment._upgrade_v1_templates(params) # Prefect appends "| tojson"
hydrate(params, HydrationContext(raise_on_error=True, render_jinja=True,
jinja_context={"event": received_event})) # received_event.id is a UUID -> TypeError
Additional Information
- Affected code:
backend/infrahub/webhook/models.py → WebhookTriggerDefinitionBuilder.build(), the event_id / event_occured_at / branch_name action parameters.
- Test gap:
backend/tests/functional/webhook/test_process.py calls webhook_process() directly with a hand-built event_payload dict, bypassing Prefect's parameter rendering; test_trigger_definition_builder.py only asserts the un-rendered parameter shape. No test exercises the render path where the crash occurs.
- Suggested fix (two verified options):
- Preferred: wrap each scalar in an explicit plain-
jinja kind, e.g. {"__prefect_kind": "jinja", "template": "{{ event.id }}"}. A dict already carrying __prefect_kind is skipped by _upgrade_v1_templates, so no | tojson is appended and the value renders as a string.
- Alternative: add
| string, e.g. {{ event.id | string }} — the auto-appended | tojson then serializes a str, which is safe.
- Environment: Infrahub 1.10.0 · Prefect 3.7.5 · Python 3.13 · observed on macOS arm64 (platform-independent — the defect is in server-side trigger-definition/parameter-render logic).
Component
API Server / GraphQL
Infrahub version
1.10.0
Current Behavior
Webhook automations fail at Prefect parameter-render time when an event fires, so the
webhook-processdeployment is never run and no HTTP request is sent. The failure happens inside Prefect's action parameter hydration, before any Infrahub webhook code executes.WebhookTriggerDefinitionBuilder.build()(backend/infrahub/webhook/models.py) emits several action parameters as bare single-expression Jinja strings:When the automation fires, Prefect's
RunDeployment.render_parameters()runs_upgrade_v1_templates(), which auto-rewrites every bare{{ … }}parameter into{{ … | tojson }}(to preserve value types through a JSON round-trip).tojsonthen callsjson.dumps()on values that are not JSON-native:event_id→event.idis aUUID→TypeError: Object of type UUID is not JSON serializable— crashes on every webhook fireevent_occured_at→event.occurredis adatetime→TypeError: Object of type datetime is not JSON serializable— crashes on every webhook firebranch_name→ resolves toChainableUndefinedwhenever the firing event's resource has noinfrahub.branch.namekey (e.g. account/login events) →TypeErrorThe error surfaces from Prefect as:
Note: the
event_payloadparameter ({{ event.payload | tojson }}) is correctly wrapped in ajson+jinjastructure and is not the cause — it renders fine.Why custom webhooks are the most visible: standard and custom webhooks share
WebhookTriggerDefinitionBuilder, soevent_id/event_occured_atbreak both. Custom webhooks additionally default toevent_type="all"(→ listen oninfrahub.*), so they also receive events lackinginfrahub.branch.nameand hit thebranch_namecrash branch too.Expected Behavior
Webhook automations render their parameters successfully for any triggering event and dispatch the configured HTTP request. Scalar parameters (
event_id,event_occured_at,branch_name) should be delivered as strings; events without a branch resource should yield an empty/absent branch rather than crashing.Steps to Reproduce
event_typeat its default (all).webhook-processautomation fail on Prefect during parameter rendering — no HTTP request reaches the target URL.Minimal mechanism reproduction (mirrors
RunDeployment.render_parameters):Additional Information
backend/infrahub/webhook/models.py→WebhookTriggerDefinitionBuilder.build(), theevent_id/event_occured_at/branch_nameaction parameters.backend/tests/functional/webhook/test_process.pycallswebhook_process()directly with a hand-builtevent_payloaddict, bypassing Prefect's parameter rendering;test_trigger_definition_builder.pyonly asserts the un-rendered parameter shape. No test exercises the render path where the crash occurs.jinjakind, e.g.{"__prefect_kind": "jinja", "template": "{{ event.id }}"}. A dict already carrying__prefect_kindis skipped by_upgrade_v1_templates, so no| tojsonis appended and the value renders as a string.| string, e.g.{{ event.id | string }}— the auto-appended| tojsonthen serializes astr, which is safe.