Describe the bug
Genie causes repeated recompilation problems, increases allocation count and makes it non-deterministic in code it should not affect e.g. OrdinaryDiffEq solvers. Furthermore, recompilations caused by Genie have extremely high values e.g. 5000%.
It seems that version 5.35.7 made it worse, but the issue still persists on 5.35.6.
To reproduce
Below is MWE code that reproduces the issue:
# Minimal Working Example: Genie 5.35.7 causes ODE solver recompilation
#
# After warming up an ODE solve (QNDF + KLUFactorization), subsequent calls
# show 0% compilation time as expected. After `import Genie.Renderer.Json: json`,
# the very next ODE solves shows recompilation and increased allocations.
#
# Root-cause hypothesis
# ---------------------
# Genie 5.35.7 added in src/JSONParser.jl (commit 7add658):
#
# const UNDEFINED_REPLACEMENT = Ref{Any}(nothing)
# const UNDEFINED_TYPE = Ref{DataType}(typeof(UNDEFINED_REPLACEMENT[]))
# typify(x::String) = x == UNDEFINED_PLACEHOLDER[] ? UNDEFINED_REPLACEMENT[] : x
#
# The module-level evaluation of `typeof(UNDEFINED_REPLACEMENT[])` dereferences
# a `Ref{Any}` holding `nothing`, triggering new @generated dispatch
# specialisations that intersect with OrdinaryDiffEq / LinearSolve / SparseArrays
# dispatch paths. This invalidates previously cached method specialisations in
# the ODE solver.
ENV["GENIE_ENV"] = "prod" # disable Revise — issue persists regardless
using OrdinaryDiffEq
using LinearSolve
using SparseArrays
# ── Simple stiff ODE (Robertson chemical kinetics) ───────────────────────────
function rober!(du, u, p, t)
y₁, y₂, y₃ = u
k₁, k₂, k₃ = p
du[1] = -k₁ * y₁ + k₃ * y₂ * y₃
du[2] = k₁ * y₁ - k₂ * y₂^2 - k₃ * y₂ * y₃
du[3] = k₂ * y₂^2
end
const JAC_SPARSITY = float(sparse(Bool[
1 1 1
1 1 1
0 1 0
]))
function run_ode()
u0 = [1.0, 0.0, 0.0]
p = (0.04, 3e7, 1e4)
tspan = (0.0, 1e5)
f = ODEFunction(rober!; jac_prototype = JAC_SPARSITY)
prob = ODEProblem(f, u0, tspan, p)
return solve(prob, QNDF(linsolve = KLUFactorization());
abstol = 1e-8, reltol = 1e-6)
end
# ── Phase 1: warm up ODE solver ───────────────────────────────────────────────
println("=== Run 1 (first compilation — expected slow) ===")
@time run_ode()
println("\n=== Run 2 (expected: 0% compilation) ===")
@time run_ode()
println("\n=== Run 3 (expected: 0% compilation) ===")
@time run_ode()
# ── Load Genie.Renderer.Json ──────────────────────────────────────────────────
println("\nLoading Genie.Renderer.Json (Genie 5.35.7)...")
import Genie.Renderer.Json: json
println("Loaded.\n")
# ── Phase 2: same ODE, same solver, same types ────────────────────────────────
println("=== Run 4 (bug: Genie 5.35.7 shows compilation here, expected 0% compilation) ===")
@time run_ode()
println("\n=== Run 5 (bug: Genie 5.35.7 shows compilation here, expected 0% compilation) ===")
@time run_ode()
println("\n=== Run 6 (bug: Genie 5.35.7 shows compilation here, expected 0% compilation) ===")
@time run_ode()
println("\n=== Version Info ===")
import Pkg
Pkg.status()
using InteractiveUtils
versioninfo()
output:
=== Run 1 (first compilation — expected slow) ===
4.144455 seconds (10.20 M allocations: 509.281 MiB, 12.61% gc time, 99.91% compilation time)
=== Run 2 (expected: 0% compilation) ===
0.000528 seconds (4.44 k allocations: 210.344 KiB)
=== Run 3 (expected: 0% compilation) ===
0.000577 seconds (4.44 k allocations: 210.344 KiB)
Loading Genie.Renderer.Json (Genie 5.35.7)...
Loaded.
=== Run 4 (bug: Genie 5.35.7 shows compilation here, expected 0% compilation) ===
0.099837 seconds (684.82 k allocations: 32.385 MiB, 198.45% compilation time: 50% of which was recompilation)
=== Run 5 (bug: Genie 5.35.7 shows compilation here, expected 0% compilation) ===
0.000664 seconds (5.47 k allocations: 261.617 KiB, 5137.18% compilation time)
=== Run 6 (bug: Genie 5.35.7 shows compilation here, expected 0% compilation) ===
0.000644 seconds (6.02 k allocations: 287.109 KiB, 5013.85% compilation time)
=== Version Info ===
Status `~/Code/MWE/GenieWorldAgeProblem/Project.toml`
[c43c736e] Genie v5.35.7
[7ed4a6bd] LinearSolve v3.65.0
[1dea7af3] OrdinaryDiffEq v6.108.0
[2f01184e] SparseArrays v1.12.0
Julia Version 1.12.5
Commit 5fe89b8ddc1 (2026-02-09 16:05 UTC)
Build Info:
Official https://julialang.org release
Platform Info:
OS: Linux (x86_64-linux-gnu)
CPU: 14 × Intel(R) Core(TM) Ultra 7 165U
WORD_SIZE: 64
LLVM: libLLVM-18.1.7 (ORCJIT, alderlake)
GC: Built with stock GC
Threads: 1 default, 1 interactive, 1 GC (on 14 virtual cores)
Expected behavior
No compilation or increased allocation count on function calls that happen after import Genie.Renderer.Json: json
Additional context
Version info provided in the output of the MWE script
Please answer these optional questions to help us understand, prioritise, and assign the issue
2/ Can you give us, in a few words, some details about the app you're building with Genie?
I am trying to host some ODE solvers via REST API and I cannot afford to lose their performance or stability when calling them from Genie.
Describe the bug
Genie causes repeated recompilation problems, increases allocation count and makes it non-deterministic in code it should not affect e.g. OrdinaryDiffEq solvers. Furthermore, recompilations caused by Genie have extremely high values e.g.
5000%.It seems that version 5.35.7 made it worse, but the issue still persists on 5.35.6.
To reproduce
Below is MWE code that reproduces the issue:
output:
Expected behavior
No compilation or increased allocation count on function calls that happen after
import Genie.Renderer.Json: jsonAdditional context
Version info provided in the output of the MWE script
Please answer these optional questions to help us understand, prioritise, and assign the issue
2/ Can you give us, in a few words, some details about the app you're building with Genie?
I am trying to host some ODE solvers via REST API and I cannot afford to lose their performance or stability when calling them from Genie.