Skip to content

bug: webhook automations crash during Prefect parameter render #9742

Description

@lancamat1

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_idevent.id is a UUIDTypeError: Object of type UUID is not JSON serializablecrashes on every webhook fire
  • event_occured_atevent.occurred is a datetimeTypeError: Object of type datetime is not JSON serializablecrashes 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

  1. Create a Custom Webhook pointing at any reachable URL, leaving event_type at its default (all).
  2. Trigger any Infrahub event (e.g. create/update a node, or any account/login event).
  3. 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.pyWebhookTriggerDefinitionBuilder.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).

Metadata

Metadata

Assignees

Labels

type/bugSomething isn't working as expected

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions