diff --git a/docs/Project.toml b/docs/Project.toml
index 1be7cf0fe..1d4371d0a 100644
--- a/docs/Project.toml
+++ b/docs/Project.toml
@@ -16,5 +16,5 @@ Documenter = "1"
 JuMP = "1"
 LinearAlgebra = "1.10"
 Logging = "1.10"
-ModelingToolkit = "9.50"
+ModelingToolkit = "9.50 - 9.76"
 Plots = "1"
diff --git a/docs/src/manual/mtk.md b/docs/src/manual/mtk.md
index 605ed0af1..477fdbb4d 100644
--- a/docs/src/manual/mtk.md
+++ b/docs/src/manual/mtk.md
@@ -23,7 +23,8 @@ the last section.
     will work for all corner cases.
 
 !!! compat
-    The example relies on features and bugfixes of `ModelingToolkit.jl` v9.50.
+    The example works on `ModelingToolkit.jl` v9.50 to 9.76 (corresponding to the following
+    `[compat]` entry: `ModelingToolkit = "9.50 - 9.76"`).
 
 We first construct and instantiate the pendulum model:
 
diff --git a/src/controller/execute.jl b/src/controller/execute.jl
index a3925111f..33fe59b0b 100644
--- a/src/controller/execute.jl
+++ b/src/controller/execute.jl
@@ -395,7 +395,7 @@ function optim_objective!(mpc::PredictiveController{NT}) where {NT<:Real}
     model, optim = mpc.estim.model, mpc.optim
     nu, Hc = model.nu, mpc.Hc 
     Z̃var::Vector{JuMP.VariableRef} = optim[:Z̃var]
-    Z̃0 = set_warmstart!(mpc, mpc.transcription, Z̃var)
+    Z̃s = set_warmstart!(mpc, mpc.transcription, Z̃var)
     set_objective_linear_coef!(mpc, Z̃var)
     try
         JuMP.optimize!(optim)
@@ -405,7 +405,7 @@ function optim_objective!(mpc::PredictiveController{NT}) where {NT<:Real}
             MOIU.reset_optimizer(optim)
             JuMP.optimize!(optim)
         else
-            rethrow(err)
+            rethrow()
         end
     end
     if !issolved(optim)
@@ -426,7 +426,7 @@ function optim_objective!(mpc::PredictiveController{NT}) where {NT<:Real}
         @debug info2debugstr(getinfo(mpc))
     end
     if iserror(optim)
-        mpc.Z̃ .= Z̃0
+        mpc.Z̃ .= Z̃s
     else
         mpc.Z̃ .= JuMP.value.(Z̃var)
     end
@@ -488,7 +488,7 @@ Call `periodsleep(mpc.estim.model)`.
 periodsleep(mpc::PredictiveController, busywait=false) = periodsleep(mpc.estim.model, busywait)
 
 """
-    setstate!(mpc::PredictiveController, x̂, P̂=nothing) -> mpc
+    setstate!(mpc::PredictiveController, x̂[, P̂]) -> mpc
 
 Call [`setstate!`](@ref) on `mpc.estim` [`StateEstimator`](@ref).
 """
diff --git a/src/controller/transcription.jl b/src/controller/transcription.jl
index 55e32dd21..7b82dff19 100644
--- a/src/controller/transcription.jl
+++ b/src/controller/transcription.jl
@@ -952,13 +952,13 @@ linconstrainteq!(::PredictiveController, ::SimModel, ::SingleShooting) = nothing
 linconstrainteq!(::PredictiveController, ::SimModel, ::MultipleShooting) = nothing
 
 @doc raw"""
-    set_warmstart!(mpc::PredictiveController, transcription::SingleShooting, Z̃var) -> Z̃0
+    set_warmstart!(mpc::PredictiveController, transcription::SingleShooting, Z̃var) -> Z̃s
 
 Set and return the warm start value of `Z̃var` for [`SingleShooting`](@ref) transcription.
 
 If supported by `mpc.optim`, it warm-starts the solver at:
 ```math
-\mathbf{ΔŨ} = 
+\mathbf{Z̃_s} = 
 \begin{bmatrix}
     \mathbf{Δu}(k+0|k-1)        \\ 
     \mathbf{Δu}(k+1|k-1)        \\ 
@@ -972,24 +972,24 @@ where ``\mathbf{Δu}(k+j|k-1)`` is the input increment for time ``k+j`` computed
 last control period ``k-1``, and ``ϵ(k-1)``, the slack variable of the last control period.
 """
 function set_warmstart!(mpc::PredictiveController, transcription::SingleShooting, Z̃var)
-    nu, Hc, Z̃0 = mpc.estim.model.nu, mpc.Hc, mpc.buffer.Z̃
+    nu, Hc, Z̃s = mpc.estim.model.nu, mpc.Hc, mpc.buffer.Z̃
     # --- input increments ΔU ---
-    Z̃0[1:(Hc*nu-nu)] .= @views mpc.Z̃[nu+1:Hc*nu]
-    Z̃0[(Hc*nu-nu+1):(Hc*nu)] .= 0
+    Z̃s[1:(Hc*nu-nu)] .= @views mpc.Z̃[nu+1:Hc*nu]
+    Z̃s[(Hc*nu-nu+1):(Hc*nu)] .= 0
     # --- slack variable ϵ ---
-    mpc.nϵ == 1 && (Z̃0[end] = mpc.Z̃[end])
-    JuMP.set_start_value.(Z̃var, Z̃0)
-    return Z̃0
+    mpc.nϵ == 1 && (Z̃s[end] = mpc.Z̃[end])
+    JuMP.set_start_value.(Z̃var, Z̃s)
+    return Z̃s
 end
 
 @doc raw"""
-    set_warmstart!(mpc::PredictiveController, transcription::MultipleShooting, Z̃var) -> Z̃0
+    set_warmstart!(mpc::PredictiveController, transcription::MultipleShooting, Z̃var) -> Z̃s
 
 Set and return the warm start value of `Z̃var` for [`MultipleShooting`](@ref) transcription.
 
 It warm-starts the solver at:
 ```math
-\mathbf{ΔŨ} =
+\mathbf{Z̃_s} =
 \begin{bmatrix}
     \mathbf{Δu}(k+0|k-1)        \\ 
     \mathbf{Δu}(k+1|k-1)        \\ 
@@ -1009,17 +1009,17 @@ last control period ``k-1``, expressed as a deviation from the operating point
 ``\mathbf{x̂_{op}}``.
 """
 function set_warmstart!(mpc::PredictiveController, transcription::MultipleShooting, Z̃var)
-    nu, nx̂, Hp, Hc, Z̃0 = mpc.estim.model.nu, mpc.estim.nx̂, mpc.Hp, mpc.Hc, mpc.buffer.Z̃
+    nu, nx̂, Hp, Hc, Z̃s = mpc.estim.model.nu, mpc.estim.nx̂, mpc.Hp, mpc.Hc, mpc.buffer.Z̃
     # --- input increments ΔU ---
-    Z̃0[1:(Hc*nu-nu)] .= @views mpc.Z̃[nu+1:Hc*nu]
-    Z̃0[(Hc*nu-nu+1):(Hc*nu)] .= 0
+    Z̃s[1:(Hc*nu-nu)] .= @views mpc.Z̃[nu+1:Hc*nu]
+    Z̃s[(Hc*nu-nu+1):(Hc*nu)] .= 0
     # --- predicted states X̂0 ---
-    Z̃0[(Hc*nu+1):(Hc*nu+Hp*nx̂-nx̂)]       .= @views mpc.Z̃[(Hc*nu+nx̂+1):(Hc*nu+Hp*nx̂)]
-    Z̃0[(Hc*nu+Hp*nx̂-nx̂+1):(Hc*nu+Hp*nx̂)] .= @views mpc.Z̃[(Hc*nu+Hp*nx̂-nx̂+1):(Hc*nu+Hp*nx̂)]
+    Z̃s[(Hc*nu+1):(Hc*nu+Hp*nx̂-nx̂)]       .= @views mpc.Z̃[(Hc*nu+nx̂+1):(Hc*nu+Hp*nx̂)]
+    Z̃s[(Hc*nu+Hp*nx̂-nx̂+1):(Hc*nu+Hp*nx̂)] .= @views mpc.Z̃[(Hc*nu+Hp*nx̂-nx̂+1):(Hc*nu+Hp*nx̂)]
     # --- slack variable ϵ ---
-    mpc.nϵ == 1 && (Z̃0[end] = mpc.Z̃[end])
-    JuMP.set_start_value.(Z̃var, Z̃0)
-    return Z̃0
+    mpc.nϵ == 1 && (Z̃s[end] = mpc.Z̃[end])
+    JuMP.set_start_value.(Z̃var, Z̃s)
+    return Z̃s
 end
 
 getΔŨ!(ΔŨ, mpc::PredictiveController, ::SingleShooting, Z̃) = (ΔŨ .= Z̃) # since mpc.P̃Δu = I
diff --git a/src/estimator/execute.jl b/src/estimator/execute.jl
index 23408995b..98b63c9e2 100644
--- a/src/estimator/execute.jl
+++ b/src/estimator/execute.jl
@@ -330,7 +330,7 @@ function validate_args(estim::StateEstimator, ym, d, u=nothing)
 end
 
 """
-    setstate!(estim::StateEstimator, x̂, P̂=nothing) -> estim
+    setstate!(estim::StateEstimator, x̂[, P̂]) -> estim
 
 Set `estim.x̂0` to `x̂ - estim.x̂op` from the argument `x̂`, and `estim.P̂` to `P̂` if applicable. 
 
diff --git a/src/estimator/mhe/execute.jl b/src/estimator/mhe/execute.jl
index 38041df00..70b5ca15a 100644
--- a/src/estimator/mhe/execute.jl
+++ b/src/estimator/mhe/execute.jl
@@ -364,7 +364,7 @@ Optimize objective of `estim` [`MovingHorizonEstimator`](@ref) and return the so
 
 If supported by `estim.optim`, it warm-starts the solver at:
 ```math
-\mathbf{Z̃} = 
+\mathbf{Z̃_s} = 
 \begin{bmatrix}
     ϵ_{k-1}                         \\
     \mathbf{x̂}_{k-1}(k-N_k+p)       \\ 
@@ -391,12 +391,12 @@ function optim_objective!(estim::MovingHorizonEstimator{NT}) where NT<:Real
     X̂0  = Vector{NT}(undef, nx̂*Nk)
     û0, ŷ0, x̄, k0 = buffer.û, buffer.ŷ, buffer.x̂, buffer.k
     ϵ_0 = estim.nϵ ≠ 0 ? estim.Z̃[begin] : empty(estim.Z̃)
-    Z̃_0 = [ϵ_0; estim.x̂0arr_old; estim.Ŵ]
-    V̂, X̂0 = predict!(V̂, X̂0, û0, k0, ŷ0, estim, model, Z̃_0)
-    J_0 = obj_nonlinprog!(x̄, estim, model, V̂, Z̃_0)
-    # initial Z̃0 with Ŵ=0 if objective or constraint function not finite :
-    isfinite(J_0) || (Z̃_0 = [ϵ_0; estim.x̂0arr_old; zeros(NT, nŵ*estim.He)])
-    JuMP.set_start_value.(Z̃var, Z̃_0)
+    Z̃s = [ϵ_0; estim.x̂0arr_old; estim.Ŵ]
+    V̂, X̂0 = predict!(V̂, X̂0, û0, k0, ŷ0, estim, model, Z̃s)
+    J_0 = obj_nonlinprog!(x̄, estim, model, V̂, Z̃s)
+    # warm-start Z̃s with Ŵ=0 if objective or constraint function not finite :
+    isfinite(J_0) || (Z̃s = [ϵ_0; estim.x̂0arr_old; zeros(NT, nŵ*estim.He)])
+    JuMP.set_start_value.(Z̃var, Z̃s)
     # ------- solve optimization problem --------------
     try
         JuMP.optimize!(optim)
@@ -428,7 +428,7 @@ function optim_objective!(estim::MovingHorizonEstimator{NT}) where NT<:Real
         @debug info2debugstr(getinfo(estim))
     end
     if iserror(optim)
-        estim.Z̃ .= Z̃_0
+        estim.Z̃ .= Z̃s
     else
         estim.Z̃ .= JuMP.value.(Z̃var)
     end
diff --git a/src/general.jl b/src/general.jl
index 90a411dbc..94ed3e63f 100644
--- a/src/general.jl
+++ b/src/general.jl
@@ -51,7 +51,7 @@ function limit_solve_time(optim::GenericModel, Ts)
         if isa(err, MOI.UnsupportedAttribute{MOI.TimeLimitSec})
             @warn "Solving time limit is not supported by the optimizer."
         else
-            rethrow(err)
+            rethrow()
         end
     end
 end
diff --git a/src/model/nonlinmodel.jl b/src/model/nonlinmodel.jl
index d6c0c5d98..25566a7c6 100644
--- a/src/model/nonlinmodel.jl
+++ b/src/model/nonlinmodel.jl
@@ -111,7 +111,7 @@ form. The optional parameter `NT` explicitly set the number type of vectors (def
 !!! warning
     The two functions must be in pure Julia to use the model in [`NonLinMPC`](@ref),
     [`ExtendedKalmanFilter`](@ref), [`MovingHorizonEstimator`](@ref) and [`linearize`](@ref),
-    except if a finite difference backend is used (e.g. [`AutoFiniteDiff`](@extref DifferentiationInterface List).
+    except if a finite difference backend is used (e.g. [`AutoFiniteDiff`](@extref DifferentiationInterface List)).
 
 See also [`LinModel`](@ref).
 
diff --git a/test/2_test_state_estim.jl b/test/2_test_state_estim.jl
index c1cb8e764..082e0c45a 100644
--- a/test/2_test_state_estim.jl
+++ b/test/2_test_state_estim.jl
@@ -1364,7 +1364,7 @@ end
     X̂_mhe = zeros(4, 6)
     X̂_kf  = zeros(4, 6)
     for i in 1:6
-        y = [50,31] #+ randn(2)
+        y = [50,31] + randn(2)
         x̂_mhe = preparestate!(mhe, y, [25])
         x̂_kf  = preparestate!(kf,  y, [25])
         X̂_mhe[:,i] = x̂_mhe