<@ULVA73B9P> - is there a way to force the prefect...
# ask-marvin
k
@Marvin - is there a way to force the prefect backend to treat a field in a pydantic model defined flow input as a float, even if the default value is "integer like". I have a model that is passed as a parameter with 10 float fields, all which have a default. Some of the defaults are values like
3.0
,
10.0
, etc. The UI and the API seem to auto-magically convert these fields back to integers (3, 10, etc). This causes flickering with the terraform provider.
m
thought for 508.4 seconds
Short answer: Not reliably. In Prefect 3.x, parameters are stored and exchanged as JSON. JSON has a single “number” type (no distinction between integers and floats), and the UI runs in JavaScript where all numbers are IEEE-754 doubles. That means values like 3.0 will often round-trip as 3, because encoders and the browser will normalize “integer-like” floats. There isn’t a supported switch in Prefect to force the API/UI to retain trailing .0. Why you’re seeing this - Your Pydantic model correctly declares the fields as float, but once those defaults are rendered in the UI or serialized back to JSON, JS/JSON will commonly drop the trailing .0. - When Terraform diffs the desired state (e.g., 3.0) against what it reads back (e.g., 3), it detects a change even though they’re numerically equivalent. Practical workarounds - Best: Normalize on the Terraform side so 3 and 3.0 are treated as equal. If you can, configure the resource to avoid diffs on numeric representation or use lifecycle ignore rules for these fields. - If representation must be stable across the API boundary, serialize as strings: - Change those fields to strings in your parameter model and coerce to float inside your flow. That preserves “3.0” exactly at the API/UI layer. Example:
Copy code
from pydantic import BaseModel, Field, field_validator

  class Params(BaseModel):
      rate: str = Field("3.0")
      # ... repeat for other fields

      @field_validator("rate", mode="before")
      def coerce_to_canonical_float_string(cls, v):
          # Accept numbers or strings, emit canonical string with one decimal
          if isinstance(v, (int, float)):
              return f"{float(v):.1f}"
          # If already a string like "3" or "3.0", normalize it
          try:
              return f"{float(v):.1f}"
          except Exception:
              return v
Then in your flow, cast to float when you use it:
float(params.rate)
. - Alternative: Use Decimal and force string serialization. This also preserves formatting but will show as a string field in the UI:
Copy code
from decimal import Decimal
  from pydantic import BaseModel, Field, field_serializer

  class Params(BaseModel):
      rate: Decimal = Field(default=Decimal("3.0"))

      @field_serializer("rate", when_used="json")
      def ser_rate(self, v: Decimal) -> str:
          return format(v, "f")  # "3.0"
Notes - Keeping these as numeric fields while guaranteeing “3.0” instead of “3” is not feasible with JSON/JS semantics; the UI (and many JSON encoders) will normalize to a canonical number representation. - If this drift is coming specifically from the Prefect Terraform provider, you may want to open an issue asking it to treat 3 and 3.0 as equivalent to avoid plan flicker. Provider link: Terraform Registry: Prefect Provider. Repo (for issues): PrefectHQ/terraform-provider-prefect. If you can share: - The provider version - A minimal example of your Pydantic model and the exact Terraform diff …I’m happy to try to reproduce and suggest the least invasive fix for your setup. Docs for reference: - Prefect parameters overview: Parameters in Prefect - Pydantic v2 JSON schema/serialization background: Pydantic JSON Schema and Serialization