Replies: 1 comment
|
oh nice rundown on the honestly, switching to OpenTelemetry with Prefect's native hooks was way smoother. I get traces into Grafana using |
|
oh nice rundown on the honestly, switching to OpenTelemetry with Prefect's native hooks was way smoother. I get traces into Grafana using |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
this was drafted by claude at my direction
Symptom
The run never leaves
Submittingin the UI, and the flow process fails while tryingto advance its own state:
Serializing the
StateCreatepayload fails, so the transition never reaches the APIand the run is stranded on
Submitting.Root cause
A pydantic
defer_buildinteraction. Prefect's state schemas (StateDetails, etc.)are built lazily, and the client serializes state with
model_dump(mode="json", serialize_as_any=True). If a nested model's serializer isleft in pydantic's incomplete (
MockValSer) state,serialize_as_any=Truefallsback to inference serialization, which then can't serialize the
uuid.UUIDfieldsin
StateDetails→Unable to serialize unknown type: <class 'uuid.UUID'>.Prefect already guards against this on its own — it rebuilds these schemas at import
time (see #18053 /
#20127). The failure reappears
when something else perturbs pydantic's build state after Prefect's rebuild.
Two things make this sharper:
serialize_as_anygot stricter in pydantic 2.12. Cases that older pydantictolerated now raise
PydanticSerializationError: Unable to serialize unknown type(see pydantic #12348,
#12379,
#12382). Prefect currently
allows pydantic 2.12, so an env on 2.12 is more exposed.
incomplete during the
prefect flow-run executesubprocess startup.This is a class of tools, not just ddtrace
ddtrace-runis the one we've seen reported, but the trigger is "zero-code agentthat wraps your entrypoint and rewrites/patches imports before your app runs."
Other tools in the same category that could interact the same way:
ddtrace-run(confirmed)opentelemetry-instrument(also uses runtime monkeypatching)newrelic-admin run-program/newrelic.agent.initialize()None of these are "wrong" — but wrapping the Prefect engine subprocess entrypoint
(
prefect flow-run execute) with a global bootstrap is the risky part, because that'sexactly where the deferred pydantic schemas get built.
The better way: lean on Prefect's native OpenTelemetry support
You almost certainly reached for
ddtrace-runto get traces of your flow runs.You don't need to wrap the engine to get that — Prefect already speaks OpenTelemetry:
traceparentyou'llnotice on flow-run labels /
StateDetails), so parent/child runs stitch together.Because Prefect uses the global OpenTelemetry API, any OTel SDK + exporter you
configure in the environment picks up Prefect's spans. To land them in Datadog:
(
OTEL_EXPORTER_OTLP_ENDPOINT,OTEL_TRACES_EXPORTER=otlp, …).with the Datadog exporter). See Datadog's
OTLP ingestion
docs.
This gives you Datadog traces (including Prefect's own flow/task spans) without
globally rewriting the engine process.
If you specifically want
ddtraceinstrumentation of your own libraries, preferscoped, programmatic patching inside your flow code
(
import ddtrace; ddtrace.patch(requests=True, ...)) over the globalddtrace-runwrapper around the engine entrypoint.
Workarounds (if you just need it working now)
pydantic<2.12while you migrate your tracing setup.If you hit this
Please share your
prefect version, yourpydanticand APM-agent(
ddtrace/opentelemetry-*/newrelic/…) versions, and the exact command thatlaunches the flow-run process. A version-pinned reproduction would help us decide
whether Prefect can harden the serialization path further so it's robust even under
aggressive import-time monkeypatching.
All reactions