Skip to content

fix(api): make run-time parameters usable on every job backend - #254

Merged
thiagoluga merged 1 commit into
masterfrom
fix/runtime-parameters-jsonelement
Aug 3, 2026
Merged

fix(api): make run-time parameters usable on every job backend#254
thiagoluga merged 1 commit into
masterfrom
fix/runtime-parameters-jsonelement

Conversation

@thiagoluga

Copy link
Copy Markdown
Owner

What

RunReportRequest.Parameters types its values as object?, so System.Text.Json materializes each one as a JsonElement. Nothing downstream can use that — an ADO provider rejects it outright:

No mapping exists from object type System.Text.Json.JsonElement to a known managed provider native type

So every parameterized report failed on the sync and in-memory job paths. The Hangfire path happened to work, because it round-trips parameters through JobParameters, which converts them — meaning the same request succeeded or failed depending on the job backend.

Confirmed empirically before fixing: a new endpoint test showed the source receiving System.Text.Json.JsonElement where a string was expected.

Values are now converted at the one boundary where they enter, reusing PrimitiveObjectConverter rather than restating "JSON value → CLR primitive".

Two fixes the equivalence exposed

  • JobParameters boxed every whole number as a double. A conditional returning a long alongside a double widens the long implicitly unless it is cast to object first — the exact trap PrimitiveObjectConverter already documents and guards. A bigint id past 2^53 was bound as a float and compared wrong on the Hangfire path. The existing test missed it because Shouldly compares numerics by value, so 42.0 satisfies ShouldBe(42L); it now asserts the runtime type.
  • A number too large for double parsed to ±Infinity, which is not representable in JSON, so re-serializing it threw. Without this, the change would have turned a previously working 202 into a 500 plus an orphaned Queued job. Such a value now keeps its original JSON token.

Verification

  • New RunParameterBindingTestsverified to fail before the fix (source got a JsonElement) and pass after.
  • Strengthened JobParametersTestsverified to fail without the object cast (should be of type … System.Double).
  • AspNetCore integration 148 passed, Jobs 34, Core 298; full solution builds clean.

Found by a bug hunt over the API layer. The remaining findings from that hunt and the HTTP-source hunt — including two that also concern parameters (complex values still diverge by backend; POST /sources property bags are unnormalized) — are recorded in docs/STATUS-AND-BACKLOG.md §6, since each needs a decision.

The run request types its parameter values as `object?`, so System.Text.Json
materialized each one as a JsonElement. Nothing downstream can use that — an ADO
provider rejects it outright ("No mapping exists from object type
System.Text.Json.JsonElement to a known managed provider native type") — so every
parameterized report failed on the sync and in-memory-job paths, while the
Hangfire path happened to work because it round-trips parameters through
JobParameters, which converts them. Convert at the one boundary where they enter,
reusing PrimitiveObjectConverter rather than restating "JSON value -> CLR
primitive".

That equivalence also required two fixes in the conversion itself:

- JobParameters boxed EVERY whole number as a double. A conditional returning a
  long alongside a double widens the long implicitly unless it is cast to object
  first — the exact trap PrimitiveObjectConverter documents. A bigint id past
  2^53 was bound as a float and compared wrong on the Hangfire path. The existing
  test missed it because Shouldly compares numerics by value, so 42.0 satisfies
  ShouldBe(42L); it now asserts the runtime type.
- A number too large for double parsed to +/-Infinity, which is not representable
  in JSON, so re-serializing it threw and would have turned a previously working
  202 into a 500 with an orphaned Queued job. Such a value now keeps its original
  JSON token.

Verified: the new endpoint test failed before the fix (the source received a
JsonElement) and passes after; the strengthened JobParameters test fails without
the object cast.
@sonarqubecloud

sonarqubecloud Bot commented Aug 3, 2026

Copy link
Copy Markdown

@sonarqubecloud

sonarqubecloud Bot commented Aug 3, 2026

Copy link
Copy Markdown

@thiagoluga
thiagoluga merged commit 8f6a7ac into master Aug 3, 2026
5 checks passed
@thiagoluga
thiagoluga deleted the fix/runtime-parameters-jsonelement branch August 3, 2026 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant