Skip to content

POI failing with Clarabel #201

Open
Open

Description

@andrewrosemberg

Observed in this environment:

Julia=1.10.1
POI=0.14.2
MOI=1.49.0
SCS=2.6.1

import MathOptInterface as MOI
import ParametricOptInterface as POI
using SCS

inner = MOI.instantiate(SCS.Optimizer; with_bridge_type = Float64, with_cache_type = Float64)
model = POI.Optimizer(inner)
MOI.set(model, MOI.Silent(), true)

x = MOI.add_variable(model)
p, _ = MOI.add_constrained_variable(model, MOI.Parameter(1.0))

f = MOI.ScalarAffineFunction(
    [MOI.ScalarAffineTerm(1.0, x), MOI.ScalarAffineTerm(-1.0, p)],
    0.0,
)
MOI.add_constraint(model, f, MOI.EqualTo(0.0))

MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
MOI.set(
    model,
    MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
    MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0),
)

println("first optimize")
MOI.optimize!(model)
println("x=", MOI.get(model, MOI.VariablePrimal(), x), " p=", MOI.get(model, POI.ParameterValue(), p))

MOI.set(model, POI.ParameterValue(), p, 2.0)
println("second optimize")
MOI.optimize!(model)  # Fails here with ModifyConstraintNotAllowed + modify_constants(::SCS._SetConstants, ...)

Activity

  1. changed the title [-]POI Failing with SCS[/-] [+]POI Failing with SCS and Clarabel[/+] on Feb 12, 2026
  2. andrewrosemberg commented on Feb 12, 2026

    @andrewrosemberg
    CollaboratorAuthor

    Actually also happening with Clarabel:

    using JuMP
    import MathOptInterface as MOI
    import ParametricOptInterface as POI
    using Clarabel
    
    opt = POI.Optimizer(
        MOI.instantiate(Clarabel.Optimizer; with_bridge_type = Float64, with_cache_type = Float64),
    )
    m = direct_model(opt)
    set_silent(m)
    
    @variable(m, x >= 0)                 # key trigger
    @variable(m, p in MOI.Parameter(1.0))
    @constraint(m, x == p)
    @objective(m, Min, x)
    
    optimize!(m)                         # works
    set_parameter_value(p, 2.0)
    optimize!(m)                         # throws SetAttributeNotAllowed{ConstraintSet}
    

    The error:

    ERROR: MathOptInterface.SetAttributeNotAllowed{MathOptInterface.ConstraintSet}:
    
    ## Cause
    
    Setting attribute MathOptInterface.ConstraintSet() cannot be performed
    
    ## Fixing this error
    
    An `MOI.NotAllowedError` error occurs when you have tried to do something that
    is not implemented by the solver.
    
    The most common way to fix this error is to wrap the optimizer in a
    `MOI.Utilities.CachingOptimizer`.
    
    For example, if you are using `JuMP.Model` or `JuMP.set_optimizer`, do:
    ``julia
    model = JuMP.Model(optimizer; with_cache_type = Float64)
    model = JuMP.GenericModel{T}(optimizer; with_cache_type = T)
    JuMP.set_optimizer(model, optimizer; with_cache_type = Float64)
    ``
    Similarly, if you are using `MOI.instantiate`, do:
    ``julia
    model = MOI.instantiate(optimizer; with_cache_type = Float64)
    ``
    
    Stacktrace:
     [1] set(b::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, attr::MathOptInterface.ConstraintSet, ci::MathOptInterface.ConstraintIndex{…}, set::MathOptInterface.EqualTo{…})
       @ MathOptInterface.Bridges /tmp/ar_julia_depot/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:1585
     [2] _update_affine_constraints!(model::ParametricOptInterface.Optimizer{…}, affine_constraint_cache_inner::MathOptInterface.Utilities.DoubleDicts.DoubleDictInner{…}, affine_constraint_cache_set_inner::MathOptInterface.Utilities.DoubleDicts.DoubleDictInner{…})
       @ ParametricOptInterface /tmp/ar_julia_depot/packages/ParametricOptInterface/qeWEl/src/update_parameters.jl:63
     [3] _update_affine_constraints!(model::ParametricOptInterface.Optimizer{…})
       @ ParametricOptInterface /tmp/ar_julia_depot/packages/ParametricOptInterface/qeWEl/src/update_parameters.jl:32
     [4] update_parameters!(model::ParametricOptInterface.Optimizer{Float64, MathOptInterface.Bridges.LazyBridgeOptimizer{…}})
       @ ParametricOptInterface /tmp/ar_julia_depot/packages/ParametricOptInterface/qeWEl/src/update_parameters.jl:293
     [5] optimize!(model::ParametricOptInterface.Optimizer{Float64, MathOptInterface.Bridges.LazyBridgeOptimizer{…}})
       @ ParametricOptInterface /tmp/ar_julia_depot/packages/ParametricOptInterface/qeWEl/src/MOI_wrapper.jl:2068
     [6] optimize!(model::Model; ignore_optimize_hook::Bool, _differentiation_backend::MathOptInterface.Nonlinear.SparseReverseMode, kwargs::@Kwargs{})
       @ JuMP /tmp/ar_julia_depot/packages/JuMP/7eD71/src/optimizer_interface.jl:609
     [7] optimize!(model::Model)
       @ JuMP /tmp/ar_julia_depot/packages/JuMP/7eD71/src/optimizer_interface.jl:560
     [8] top-level scope
       @ REPL[35]:1
    Some type information was truncated. Use `show(err)` to see complete types.
    
  3. andrewrosemberg commented on Feb 12, 2026

    @andrewrosemberg
    CollaboratorAuthor

    I first saw this using DiffOpt:

    using JuMP, DiffOpt, Clarabel
    import MathOptInterface as MOI
    
    m = DiffOpt.diff_model(Clarabel.Optimizer)
    @variable(m, x >= 0.0)
    @variable(m, y)
    @variable(m, sout)
    @variable(m, d)
    @variable(m, nd)
    @variable(m, sin in MOI.Parameter(5.0))
    @variable(m, starget in MOI.Parameter(4.0))
    @variable(m, unc in MOI.Parameter(2.0))
    
    @constraint(m, sout == sin + unc - x)
    @constraint(m, x + y >= 10)
    @constraint(m, d == sout - starget)
    @constraint(m, [nd; d] in SecondOrderCone())
    @objective(m, Min, 30y + 1e4*nd)
    
    optimize!(m)  # works
    set_parameter_value(sin, 9.0)
    set_parameter_value(starget, 7.0)
    set_parameter_value(unc, 2.0)
    optimize!(m)  # fails with SetAttributeNotAllowed{ConstraintSet}
    
  4. odow commented on Feb 12, 2026

    @odow
    Member

    Here's the full error for SCS. We're not triggering the cache rebuild because we hit a MethodError instead of a NotAllowedError.

    julia> using JuMP
    
    julia> import ParametricOptInterface as POI
    
    julia> import SCS
    
    julia> begin
               inner = MOI.instantiate(SCS.Optimizer; with_bridge_type = Float64, with_cache_type = Float64)
               model = Model(() -> POI.Optimizer(inner))
               set_silent(model)
               @variable(model, x)
               @variable(model, p in Parameter(1.0))
               @constraint(model, x <= p)
               optimize!(model)
               set_parameter_value(p, 2.0)
               optimize!(model) 
           end
    ERROR: MathOptInterface.ModifyConstraintNotAllowed{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives, MathOptInterface.VectorConstantChange{Float64}}:
    
    ## Cause
    
    Modifying the constraints MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}(1) with MathOptInterface.VectorConstantChange{Float64}([2.0]) cannot be performed
    
    ## Fixing this error
    
    An `MOI.NotAllowedError` error occurs when you have tried to do something that
    is not implemented by the solver.
    
    The most common way to fix this error is to wrap the optimizer in a
    `MOI.Utilities.CachingOptimizer`.
    
    For example, if you are using `JuMP.Model` or `JuMP.set_optimizer`, do:
    ```julia
    model = JuMP.Model(optimizer; with_cache_type = Float64)
    model = JuMP.GenericModel{T}(optimizer; with_cache_type = T)
    JuMP.set_optimizer(model, optimizer; with_cache_type = Float64)
    ```
    Similarly, if you are using `MOI.instantiate`, do:
    ```julia
    model = MOI.instantiate(optimizer; with_cache_type = Float64)
    ```
    
    Stacktrace:
      [1] modify(model::MathOptInterface.Utilities.MatrixOfConstraints{…}, ci::MathOptInterface.ConstraintIndex{…}, change::MathOptInterface.VectorConstantChange{…})
        @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/Q3V1z/src/Utilities/matrix_of_constraints.jl:696
      [2] modify(model::MathOptInterface.Utilities.GenericModel{…}, ci::MathOptInterface.ConstraintIndex{…}, change::MathOptInterface.VectorConstantChange{…})
        @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/Q3V1z/src/Utilities/model.jl:565
      [3] modify(uf::MathOptInterface.Utilities.UniversalFallback{…}, ci::MathOptInterface.ConstraintIndex{…}, change::MathOptInterface.VectorConstantChange{…})
        @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/Q3V1z/src/Utilities/universalfallback.jl:863
      [4] modify(m::MathOptInterface.Utilities.CachingOptimizer{…}, cindex::MathOptInterface.ConstraintIndex{…}, change::MathOptInterface.VectorConstantChange{…})
        @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/Q3V1z/src/Utilities/cachingoptimizer.jl:596
      [5] modify
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:2233 [inlined]
      [6] set(model::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, ::MathOptInterface.ConstraintSet, bridge::MathOptInterface.Bridges.Constraint.VectorizeBridge{…}, new_set::MathOptInterface.GreaterThan{…})
        @ MathOptInterface.Bridges.Constraint ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/Constraint/bridges/VectorizeBridge.jl:218
      [7] (::MathOptInterface.Bridges.var"#call_in_context##2#call_in_context##3"{…})(bridge::MathOptInterface.Bridges.Constraint.VectorizeBridge{…})
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:324
      [8] (::MathOptInterface.Bridges.var"#call_in_context##0#call_in_context##1"{…})()
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:309
      [9] call_in_context(map::MathOptInterface.Bridges.Variable.Map, bridge_index::Int64, f::MathOptInterface.Bridges.var"#call_in_context##0#call_in_context##1"{…})
        @ MathOptInterface.Bridges.Variable ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/Variable/map.jl:621
     [10] call_in_context
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/Variable/map.jl:652 [inlined]
     [11] call_in_context
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:306 [inlined]
     [12] call_in_context
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:321 [inlined]
     [13] _set_substituted(b::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, attr::MathOptInterface.ConstraintSet, ci::MathOptInterface.ConstraintIndex{…}, value::MathOptInterface.GreaterThan{…})
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:1509
     [14] set(b::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, attr::MathOptInterface.ConstraintSet, ci::MathOptInterface.ConstraintIndex{…}, set::MathOptInterface.GreaterThan{…})
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:1592
     [15] set
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/Constraint/set_map.jl:152 [inlined]
     [16] (::MathOptInterface.Bridges.var"#call_in_context##2#call_in_context##3"{…})(bridge::MathOptInterface.Bridges.Constraint.LessToGreaterBridge{…})
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:324
     [17] (::MathOptInterface.Bridges.var"#call_in_context##0#call_in_context##1"{…})()
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:309
     [18] call_in_context(map::MathOptInterface.Bridges.Variable.Map, bridge_index::Int64, f::MathOptInterface.Bridges.var"#call_in_context##0#call_in_context##1"{…})
        @ MathOptInterface.Bridges.Variable ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/Variable/map.jl:621
     [19] call_in_context
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/Variable/map.jl:652 [inlined]
     [20] call_in_context
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:306 [inlined]
     [21] call_in_context
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:321 [inlined]
     [22] _set_substituted(b::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, attr::MathOptInterface.ConstraintSet, ci::MathOptInterface.ConstraintIndex{…}, value::MathOptInterface.LessThan{…})
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:1509
     [23] set(b::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, attr::MathOptInterface.ConstraintSet, ci::MathOptInterface.ConstraintIndex{…}, set::MathOptInterface.LessThan{…})
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:1592
     [24] _update_affine_constraints!(model::ParametricOptInterface.Optimizer{…}, affine_constraint_cache_inner::MathOptInterface.Utilities.DoubleDicts.DoubleDictInner{…}, affine_constraint_cache_set_inner::MathOptInterface.Utilities.DoubleDicts.DoubleDictInner{…})
        @ ParametricOptInterface ~/.julia/packages/ParametricOptInterface/qeWEl/src/update_parameters.jl:63
     [25] _update_affine_constraints!(model::ParametricOptInterface.Optimizer{…})
        @ ParametricOptInterface ~/.julia/packages/ParametricOptInterface/qeWEl/src/update_parameters.jl:32
     [26] update_parameters!(model::ParametricOptInterface.Optimizer{Float64, MathOptInterface.Bridges.LazyBridgeOptimizer{…}})
        @ ParametricOptInterface ~/.julia/packages/ParametricOptInterface/qeWEl/src/update_parameters.jl:293
     [27] optimize!(model::ParametricOptInterface.Optimizer{Float64, MathOptInterface.Bridges.LazyBridgeOptimizer{…}})
        @ ParametricOptInterface ~/.julia/packages/ParametricOptInterface/qeWEl/src/MOI_wrapper.jl:2068
     [28] optimize!
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:367 [inlined]
     [29] optimize!(m::MathOptInterface.Utilities.CachingOptimizer{…})
        @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/Q3V1z/src/Utilities/cachingoptimizer.jl:379
     [30] optimize!(model::Model; ignore_optimize_hook::Bool, _differentiation_backend::MathOptInterface.Nonlinear.SparseReverseMode, kwargs::@Kwargs{})
        @ JuMP ~/.julia/packages/JuMP/7eD71/src/optimizer_interface.jl:609
     [31] optimize!(model::Model)
        @ JuMP ~/.julia/packages/JuMP/7eD71/src/optimizer_interface.jl:560
     [32] top-level scope
        @ REPL[49]:10
    
    caused by: MethodError: no method matching modify_constants(::SCS._SetConstants{Float64}, ::UnitRange{Int64}, ::Vector{Float64})
    The function `modify_constants` exists, but no method is defined for this combination of argument types.
    
    Closest candidates are:
      modify_constants(::AbstractVector{T}, ::AbstractVector{<:Integer}, ::AbstractVector{T}) where T
       @ MathOptInterface ~/.julia/packages/MathOptInterface/Q3V1z/src/Utilities/matrix_of_constraints.jl:710
      modify_constants(::AbstractVector{T}, ::Integer, ::T) where T
       @ MathOptInterface ~/.julia/packages/MathOptInterface/Q3V1z/src/Utilities/matrix_of_constraints.jl:701
    
    Stacktrace:
      [1] modify(model::MathOptInterface.Utilities.MatrixOfConstraints{…}, ci::MathOptInterface.ConstraintIndex{…}, change::MathOptInterface.VectorConstantChange{…})
        @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/Q3V1z/src/Utilities/matrix_of_constraints.jl:694
      [2] modify(model::MathOptInterface.Utilities.GenericModel{…}, ci::MathOptInterface.ConstraintIndex{…}, change::MathOptInterface.VectorConstantChange{…})
        @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/Q3V1z/src/Utilities/model.jl:565
      [3] modify(uf::MathOptInterface.Utilities.UniversalFallback{…}, ci::MathOptInterface.ConstraintIndex{…}, change::MathOptInterface.VectorConstantChange{…})
        @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/Q3V1z/src/Utilities/universalfallback.jl:863
      [4] modify(m::MathOptInterface.Utilities.CachingOptimizer{…}, cindex::MathOptInterface.ConstraintIndex{…}, change::MathOptInterface.VectorConstantChange{…})
        @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/Q3V1z/src/Utilities/cachingoptimizer.jl:596
      [5] modify
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:2233 [inlined]
      [6] set(model::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, ::MathOptInterface.ConstraintSet, bridge::MathOptInterface.Bridges.Constraint.VectorizeBridge{…}, new_set::MathOptInterface.GreaterThan{…})
        @ MathOptInterface.Bridges.Constraint ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/Constraint/bridges/VectorizeBridge.jl:218
      [7] (::MathOptInterface.Bridges.var"#call_in_context##2#call_in_context##3"{…})(bridge::MathOptInterface.Bridges.Constraint.VectorizeBridge{…})
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:324
      [8] (::MathOptInterface.Bridges.var"#call_in_context##0#call_in_context##1"{…})()
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:309
      [9] call_in_context(map::MathOptInterface.Bridges.Variable.Map, bridge_index::Int64, f::MathOptInterface.Bridges.var"#call_in_context##0#call_in_context##1"{…})
        @ MathOptInterface.Bridges.Variable ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/Variable/map.jl:621
     [10] call_in_context
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/Variable/map.jl:652 [inlined]
     [11] call_in_context
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:306 [inlined]
     [12] call_in_context
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:321 [inlined]
     [13] _set_substituted(b::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, attr::MathOptInterface.ConstraintSet, ci::MathOptInterface.ConstraintIndex{…}, value::MathOptInterface.GreaterThan{…})
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:1509
     [14] set(b::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, attr::MathOptInterface.ConstraintSet, ci::MathOptInterface.ConstraintIndex{…}, set::MathOptInterface.GreaterThan{…})
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:1592
     [15] set
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/Constraint/set_map.jl:152 [inlined]
     [16] (::MathOptInterface.Bridges.var"#call_in_context##2#call_in_context##3"{…})(bridge::MathOptInterface.Bridges.Constraint.LessToGreaterBridge{…})
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:324
     [17] (::MathOptInterface.Bridges.var"#call_in_context##0#call_in_context##1"{…})()
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:309
     [18] call_in_context(map::MathOptInterface.Bridges.Variable.Map, bridge_index::Int64, f::MathOptInterface.Bridges.var"#call_in_context##0#call_in_context##1"{…})
        @ MathOptInterface.Bridges.Variable ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/Variable/map.jl:621
     [19] call_in_context
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/Variable/map.jl:652 [inlined]
     [20] call_in_context
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:306 [inlined]
     [21] call_in_context
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:321 [inlined]
     [22] _set_substituted(b::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, attr::MathOptInterface.ConstraintSet, ci::MathOptInterface.ConstraintIndex{…}, value::MathOptInterface.LessThan{…})
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:1509
     [23] set(b::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, attr::MathOptInterface.ConstraintSet, ci::MathOptInterface.ConstraintIndex{…}, set::MathOptInterface.LessThan{…})
        @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:1592
     [24] _update_affine_constraints!(model::ParametricOptInterface.Optimizer{…}, affine_constraint_cache_inner::MathOptInterface.Utilities.DoubleDicts.DoubleDictInner{…}, affine_constraint_cache_set_inner::MathOptInterface.Utilities.DoubleDicts.DoubleDictInner{…})
        @ ParametricOptInterface ~/.julia/packages/ParametricOptInterface/qeWEl/src/update_parameters.jl:63
     [25] _update_affine_constraints!(model::ParametricOptInterface.Optimizer{…})
        @ ParametricOptInterface ~/.julia/packages/ParametricOptInterface/qeWEl/src/update_parameters.jl:32
     [26] update_parameters!(model::ParametricOptInterface.Optimizer{Float64, MathOptInterface.Bridges.LazyBridgeOptimizer{…}})
        @ ParametricOptInterface ~/.julia/packages/ParametricOptInterface/qeWEl/src/update_parameters.jl:293
     [27] optimize!(model::ParametricOptInterface.Optimizer{Float64, MathOptInterface.Bridges.LazyBridgeOptimizer{…}})
        @ ParametricOptInterface ~/.julia/packages/ParametricOptInterface/qeWEl/src/MOI_wrapper.jl:2068
     [28] optimize!
        @ ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:367 [inlined]
     [29] optimize!(m::MathOptInterface.Utilities.CachingOptimizer{…})
        @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/Q3V1z/src/Utilities/cachingoptimizer.jl:379
     [30] optimize!(model::Model; ignore_optimize_hook::Bool, _differentiation_backend::MathOptInterface.Nonlinear.SparseReverseMode, kwargs::@Kwargs{})
        @ JuMP ~/.julia/packages/JuMP/7eD71/src/optimizer_interface.jl:609
     [31] optimize!(model::Model)
        @ JuMP ~/.julia/packages/JuMP/7eD71/src/optimizer_interface.jl:560
     [32] top-level scope
        @ REPL[49]:10
    Some type information was truncated. Use `show(err)` to see complete types.
  5. odow commented on Feb 12, 2026

    @odow
    Member

    The Clarabel one is slightly different

    julia> using JuMP
    
    julia> import ParametricOptInterface as POI
    
    julia> import Clarabel
    
    julia> begin
               inner = MOI.instantiate(Clarabel.Optimizer; with_bridge_type = Float64, with_cache_type = Float64)
               model = direct_model(POI.Optimizer(inner))
               set_silent(model)
               @variable(model, x >= 0)
               @variable(model, p in Parameter(1.0))
               @constraint(model, x == p)
               optimize!(model)
               set_parameter_value(p, 2.0)
               optimize!(model) 
           end
    ERROR: MathOptInterface.SetAttributeNotAllowed{MathOptInterface.ConstraintSet}:
    
    ## Cause
    
    Setting attribute MathOptInterface.ConstraintSet() cannot be performed
    
    ## Fixing this error
    
    An `MOI.NotAllowedError` error occurs when you have tried to do something that
    is not implemented by the solver.
    
    The most common way to fix this error is to wrap the optimizer in a
    `MOI.Utilities.CachingOptimizer`.
    
    For example, if you are using `JuMP.Model` or `JuMP.set_optimizer`, do:
    ```julia
    model = JuMP.Model(optimizer; with_cache_type = Float64)
    model = JuMP.GenericModel{T}(optimizer; with_cache_type = T)
    JuMP.set_optimizer(model, optimizer; with_cache_type = Float64)
    ```
    Similarly, if you are using `MOI.instantiate`, do:
    ```julia
    model = MOI.instantiate(optimizer; with_cache_type = Float64)
    ```
    
    Stacktrace:
     [1] set(b::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, attr::MathOptInterface.ConstraintSet, ci::MathOptInterface.ConstraintIndex{…}, set::MathOptInterface.EqualTo{…})
       @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/bridge_optimizer.jl:1585
     [2] _update_affine_constraints!(model::ParametricOptInterface.Optimizer{…}, affine_constraint_cache_inner::MathOptInterface.Utilities.DoubleDicts.DoubleDictInner{…}, affine_constraint_cache_set_inner::MathOptInterface.Utilities.DoubleDicts.DoubleDictInner{…})
       @ ParametricOptInterface ~/.julia/packages/ParametricOptInterface/qeWEl/src/update_parameters.jl:63
     [3] _update_affine_constraints!(model::ParametricOptInterface.Optimizer{…})
       @ ParametricOptInterface ~/.julia/packages/ParametricOptInterface/qeWEl/src/update_parameters.jl:32
     [4] update_parameters!(model::ParametricOptInterface.Optimizer{Float64, MathOptInterface.Bridges.LazyBridgeOptimizer{…}})
       @ ParametricOptInterface ~/.julia/packages/ParametricOptInterface/qeWEl/src/update_parameters.jl:293
     [5] optimize!(model::ParametricOptInterface.Optimizer{Float64, MathOptInterface.Bridges.LazyBridgeOptimizer{…}})
       @ ParametricOptInterface ~/.julia/packages/ParametricOptInterface/qeWEl/src/MOI_wrapper.jl:2068
     [6] optimize!(model::Model; ignore_optimize_hook::Bool, _differentiation_backend::MathOptInterface.Nonlinear.SparseReverseMode, kwargs::@Kwargs{})
       @ JuMP ~/.julia/packages/JuMP/7eD71/src/optimizer_interface.jl:609
     [7] optimize!(model::Model)
       @ JuMP ~/.julia/packages/JuMP/7eD71/src/optimizer_interface.jl:560
     [8] top-level scope
       @ REPL[70]:10
    Some type information was truncated. Use `show(err)` to see complete types.
  6. odow commented on Feb 12, 2026

    @odow
    Member

    I think these are all related to the fact that the parameter constraints are scalars, so they're getting bridged and modified in weird orders.

  7. odow commented on Feb 12, 2026

    @odow
    Member

    Okay. I've fixed the SCS error: jump-dev/SCS.jl#342

    The Clarabel issue seems to be jump-dev/MathOptInterface.jl#2472. I'll take a better look.

  8. odow commented on Feb 12, 2026

    @odow
    Member

    So I think the Clarabel issue is that there is a bridge inside the POI.Optimizer.

    It works if you move the required bridges outside POI:

    using JuMP
    import MathOptInterface as MOI
    import ParametricOptInterface as POI
    using Clarabel
    model = Model() do
        inner = MOI.instantiate(Clarabel.Optimizer; with_cache_type = Float64)
        return POI.Optimizer(inner)
    end
    @variable(model, x >= 0)
    @variable(model, p in MOI.Parameter(1.0))
    @constraint(model, x == p)
    @objective(model, Min, x)
    optimize!(model)
    set_parameter_value(p, 2.0)
    optimize!(model)

    So then POI+Clarabel are operating on this model:

    julia> print(backend(model).optimizer.model)
    Minimize ScalarAffineFunction{Float64}:
     0.0 + 1.0 v[1]
    
    Subject to:
    
    VariableIndex-in-Parameter{Float64}
     p ∈ Parameter{Float64}(2.0)
    
    VectorOfVariables-in-Nonnegatives
     ┌    ┐
     │v[1]│
     └    ┘ ∈ Nonnegatives(1)
    
    VectorAffineFunction{Float64}-in-Zeros
     ┌               ┐
     │-2.0 + 1.0 v[1]│
     └               ┘ ∈ Zeros(1)
  9. andrewrosemberg commented on Feb 13, 2026

    @andrewrosemberg
    CollaboratorAuthor

    I think these are all related to the fact that the parameter constraints are scalars, so they're getting bridged and modified in weird orders.

    I have a bad memory, but I think this was done because, at the time, we couldn't change multiple constants with MOI at once right? if this is no longer the case, should I try to update POI?

  10. changed the title [-]POI Failing with SCS and Clarabel[/-] [+]POI failing with Clarabel[/+] on Feb 15, 2026
  11. odow commented on Feb 17, 2026

    @odow
    Member

    The SCS issue had been hiding from us because of

    .

    I'm taking a look.

  12. odow commented on Feb 18, 2026

    @odow
    Member

    I found the cause of our problems:

    julia> using JuMP, SCS
    
    julia> import ParametricOptInterface as POI
    
    julia> model = MOI.Bridges.full_bridge_optimizer(
               POI.Optimizer(SCS.Optimizer),
               Float64,
           )
    MOIB.LazyBridgeOptimizer{ParametricOptInterface.Optimizer{Float64, MOIU.CachingOptimizer{SCS.Optimizer, MOIU.UniversalFallback{MOIU.Model{Float64}}}}}
    ├ Variable bridges: none
    ├ Constraint bridges: none
    ├ Objective bridges: none
    └ model: ParametricOptInterface.Optimizer{Float64, MOIU.CachingOptimizer{SCS.Optimizer, MOIU.UniversalFallback{MOIU.Model{Float64}}}}
      ├ ObjectiveSense: FEASIBILITY_SENSE
      ├ ObjectiveFunctionType: MOI.ScalarAffineFunction{Float64}
      ├ NumberOfVariables: 0
      └ NumberOfConstraints: 0
    
    julia> x = MOI.add_variable(model)
    MOI.VariableIndex(1)
    
    julia> p, _ = MOI.add_constrained_variable(model, MOI.Parameter(1.0))
    (MOI.VariableIndex(4611686018427387905), MathOptInterface.ConstraintIndex{MathOptInterface.VariableIndex, MathOptInterface.Parameter{Float64}}(4611686018427387905))
    
    julia> f = MOI.Utilities.vectorize([x, 1.0 * p, x])
    ┌                                                ┐
    │0.0 + 1.0 MOI.VariableIndex(1)                  │
    │0.0 + 1.0 MOI.VariableIndex(4611686018427387905)│
    │0.0 + 1.0 MOI.VariableIndex(1)                  │
    └                                                ┘
    
    julia> MOI.add_constraint(model, f, MOI.PositiveSemidefiniteConeTriangle(2))
    MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.PositiveSemidefiniteConeTriangle}(2)
    
    julia> MOI.optimize!(model)
    ------------------------------------------------------------------
    	       SCS v3.2.11 - Splitting Conic Solver
    	(c) Brendan O'Donoghue, Stanford University, 2012
    ------------------------------------------------------------------
    problem:  variables n: 1, constraints m: 3
    cones: 	  s: psd vars: 3, ssize: 1
    settings: eps_abs: 1.0e-04, eps_rel: 1.0e-04, eps_infeas: 1.0e-07
    	  alpha: 1.50, scale: 1.00e-01, adaptive_scale: 1
    	  max_iters: 100000, normalize: 1, rho_x: 1.00e-06
    	  acceleration_lookback: 10, acceleration_interval: 10
    	  compiled with openmp parallelization enabled
    lin-sys:  sparse-direct-amd-qdldl
    	  nnz(A): 2, nnz(P): 0
    ------------------------------------------------------------------
     iter | pri res | dua res |   gap   |   obj   |  scale  | time (s)
    ------------------------------------------------------------------
         0| 1.00e+00  3.00e-01  3.00e-01  1.50e-01  1.00e-01  2.07e-04 
        25| 4.71e-08  8.69e-17  0.00e+00  0.00e+00  1.00e-01  2.91e-04 
    ------------------------------------------------------------------
    status:  solved
    timings: total: 2.95e-04s = setup: 6.52e-05s + solve: 2.30e-04s
    	 lin-sys: 5.20e-06s, cones: 3.07e-05s, accel: 9.54e-07s
    ------------------------------------------------------------------
    objective = 0.000000
    ------------------------------------------------------------------
    
    julia> MOI.Bridges.print_active_bridges(model)
     * Supported objective: MOI.ScalarAffineFunction{Float64}
    ERROR: KeyError: key (MathOptInterface.Parameter{Float64},) not found
    Stacktrace:
     [1] getindex
       @ ~/.julia/packages/OrderedCollections/Xihhq/src/ordered_dict.jl:387 [inlined]
     [2] print_active_bridges(io::Base.TTY, b::MathOptInterface.Bridges.LazyBridgeOptimizer{…}, ::Type{…}, ::Type{…}, offset::String)
       @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/debug.jl:664
     [3] print_active_bridges(io::Base.TTY, b::MathOptInterface.Bridges.LazyBridgeOptimizer{ParametricOptInterface.Optimizer{…}}, ::Type{MathOptInterface.VariableIndex}, ::Type{MathOptInterface.Parameter{…}})
       @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/debug.jl:641
     [4] print_active_bridges(io::Base.TTY, b::MathOptInterface.Bridges.LazyBridgeOptimizer{ParametricOptInterface.Optimizer{Float64, MathOptInterface.Utilities.CachingOptimizer{…}}})
       @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/debug.jl:550
     [5] print_active_bridges(::MathOptInterface.Bridges.LazyBridgeOptimizer{ParametricOptInterface.Optimizer{Float64, MathOptInterface.Utilities.CachingOptimizer{…}}})
       @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Q3V1z/src/Bridges/debug.jl:556
     [6] top-level scope
       @ REPL[74]:1
    Some type information was truncated. Use `show(err)` to see complete types.

    This function makes an incorrect assumption for the case where F==VariableIndex and we support add_constrained_variable(model, ::S) but not add_constraint(model, ::F, ::S):

    https://github.com/jump-dev/MathOptInterface.jl/blob/b12036d7798d3a7cc685de9b3a3989e35b841066/src/Bridges/lazy_bridge_optimizer.jl#L456-L462

    I need to think about this more.

  13. odow commented on Feb 19, 2026

    @odow
    Member

    This is a rabbit hole. I'm just going all over the place: jump-dev/Ipopt.jl#528

    I think this is also just a combination of bugs in print_active_bridges. PR in the works.

  14. joaquimg commented on Mar 23, 2026

    @joaquimg
    Member

    @odow Do you have an update on this?

  15. odow commented on Mar 23, 2026

    @odow
    Member

    No, I fixed the print_active_bridges, but not the underlying failure with MOI.set(model, MOI.ConstraintSet(), ...)

    The offending line is:

    https://github.com/jump-dev/MathOptInterface.jl/blob/b5778d01ec690e5514630ff2a2fe51ae0bd480f0/src/Bridges/bridge_optimizer.jl#L1570-L1586

  16. blegat commented on Mar 24, 2026

    @blegat
    Member

    Which variable bridge is being used ? I don't expect Clarabel to use variable bridges since it uses the geometric conic form (aka image form)

  17. odow commented on Mar 25, 2026

    @odow
    Member

    It uses https://github.com/jump-dev/MathOptInterface.jl/blob/master/src/Bridges/Variable/bridges/VectorizeBridge.jl

    julia> MOI.Bridges.print_active_bridges(backend(model).optimizer)
     * Supported objective: MOI.ScalarAffineFunction{Float64}
     * Unsupported constraint: MOI.ScalarAffineFunction{Float64}-in-MOI.EqualTo{Float64}
     |  bridged by:
     |   MOIB.Constraint.VectorizeBridge{Float64, MOI.VectorAffineFunction{Float64}, MOI.Zeros, MOI.ScalarAffineFunction{Float64}}
     |  may introduce:
     |   * Supported constraint: MOI.VectorAffineFunction{Float64}-in-MOI.Zeros
     * Unsupported variable: MOI.GreaterThan{Float64}
     |  bridged by:
     |    MOIB.Variable.VectorizeBridge{Float64, MOI.Nonnegatives}
     |  may introduce:
     |   * Supported variable: MOI.Nonnegatives

    I really wonder if that bridge was a mistake sometimes. It adds so much complexity all over the place.

  18. blegat commented on Mar 25, 2026

    @blegat
    Member

    By making sure the solvers use the geometric form (which is also the direction mosek is taking), we shouldn't have variables bridges. Here, there are probably two equivalent way to reformulate of equal bridging cost and one of them with variable bridges. Maybe we should only use variable bridges only if the cost is strictly smaller that without variable bridges ?

  19. odow commented on Mar 25, 2026

    @odow
    Member

    Maybe we should only use variable bridges only if the cost is strictly smaller that without variable bridges ?

    Let me take a look. I would be super keen for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions