Skip to content

Raise Gurobi's own error message when it fails before finding a solution - #3574

Merged
Transurgeon merged 1 commit into
cvxpy:masterfrom
nicoloangileri:fix/gurobi-solver-error
Oct 26, 2026
Merged

Transurgeon merged 1 commit into
cvxpy:masterfrom
nicoloangileri:fix/gurobi-solver-error

Conversation

@nicoloangileri

Copy link
Copy Markdown
Contributor

Description

When gurobipy raises a GurobiError inside optimize(), both GUROBI interfaces (gurobi_qpif.py and gurobi_conif.py) catch it together with every other exception and return SOLVER_ERROR. The user then only sees the generic message:

cvxpy.error.SolverError: Solver 'GUROBI' failed. Try another solver, or solve with verbose=True for more information.

The most common case is a size-limited license (the pip gurobipy one). Gurobi's own message says exactly what is wrong, but it gets lost:

import cvxpy as cp
x = cp.Variable(2001)
cp.Problem(cp.Minimize(cp.sum(x)), [x >= 0]).solve(solver=cp.GUROBI)

With this PR, both interfaces re-raise the GurobiError as a SolverError with Gurobi's message, chained with from e, when no solution was found:

cvxpy.error.SolverError: Solver 'GUROBI' failed: Model too large for size-limited license; visit https://gurobi.com/unrestricted for more information

If Gurobi found a solution before the error (SolCount > 0), the current behaviour is kept. The HiGHS and OSQP interfaces already follow the same raise SolverError(e) pattern.

Tests: test_gurobi_error_message in test_qp_solvers.py (LP path) and in TestGUROBI in test_conic_solvers.py (SOCP path). Both patch gurobipy.Model.optimize to raise the license error, so they don't depend on the installed license. Both fail on master and pass with this change. I also checked the snippet above against a real restricted license, through both the QP and the conic path.

Issue link (if applicable): addresses part of #1548, the Gurobi case reported in this comment. The issue is broader than that: unpacking solver metadata before raising. CPLEX and COPT swallow errors around the solve call in the same way, and SCIP only logs a warning. These could be follow-ups.

Type of change

  • New feature (backwards compatible)
  • New feature (breaking API changes)
  • Bug fix
  • Other (Documentation, CI, ...)

Contribution checklist

  • Add our license to new files.
  • Check that your code adheres to our coding style.
  • Write unittests.
  • Run the unittests and check that they’re passing.
  • Run the benchmarks to make sure your change doesn’t introduce a regression.

When gurobipy raises a GurobiError during optimize() (for example a
size-limited license refusing the model), both GUROBI interfaces caught
it together with every other exception and returned a SOLVER_ERROR,
so users only saw the generic "Solver 'GUROBI' failed" message.

Re-raise it as a SolverError carrying Gurobi's message when no solution
was found. If Gurobi had found a solution before the error, keep the
existing behaviour.
@github-actions

Copy link
Copy Markdown
Contributor

Benchmarks that have stayed the same:

Change Before [8280648] After [3599539] Ratio Benchmark (Parameter)
1.06±0.1s 1.13±0.09s 1.07 gini_portfolio.Yitzhaki.time_compile_problem
2.49±0.05s 2.56±0.01s 1.03 quantum_hilbert_matrix.QuantumHilbertMatrix.time_compile_problem
1.20±0.02s 1.23±0.04s 1.02 semidefinite_programming.SemidefiniteProgramming.time_compile_problem
2.27±0.01s 2.31±0.03s 1.02 slow_pruning_1668_benchmark.SlowPruningBenchmark.time_compile_problem
5.01±0.04s 5.04±0.01s 1.01 huber_regression.HuberRegression.time_compile_problem
3.70±0.02s 3.74±0s 1.01 simple_QP_benchmarks.LeastSquares.time_compile_problem
5.63±0.02s 5.67±0.03s 1.01 simple_QP_benchmarks.UnconstrainedQP.time_compile_problem
1.17±0.02s 1.18±0.03s 1.01 tv_inpainting.TvInpainting.time_compile_problem
4.65±0.01s 4.67±0.02s 1 matrix_stuffing.ConeMatrixStuffingBench.time_compile_problem
2.92±0.03s 2.91±0.05s 1 matrix_stuffing.SmallMatrixStuffing.time_compile_problem
36.0±0.1s 36.0±0.2s 1 sdp_segfault_1132_benchmark.SDPSegfault1132Benchmark.time_compile_problem
594±2ms 594±5ms 1 simple_LP_benchmarks.SimpleFullyParametrizedLPBenchmark.time_compile_problem
12.5±0.04s 12.5±0.1s 1 simple_LP_benchmarks.SimpleLPBenchmark.time_compile_problem
1.53±0.04s 1.53±0.06s 1 simple_LP_benchmarks.SimpleScalarParametrizedLPBenchmark.time_compile_problem
3.63±0s 3.63±0.01s 1 simple_QP_benchmarks.ParametrizedQPBenchmark.time_compile_problem
5.57±0.03s 5.58±0.04s 1 simple_QP_benchmarks.SimpleQPBenchmark.time_compile_problem
6.63±0.03s 6.65±0.01s 1 svm_l1_regularization.SVMWithL1Regularization.time_compile_problem
3.24±0.01s 3.22±0.03s 0.99 optimal_advertising.OptimalAdvertising.time_compile_problem
2.58±0.1s 2.52±0.09s 0.98 finance.FactorCovarianceModel.time_compile_problem
1.11±0.01s 1.09±0.01s 0.98 matrix_stuffing.ParamConeMatrixStuffing.time_compile_problem
2.74±0.04s 2.68±0.06s 0.98 matrix_stuffing.ParamSmallMatrixStuffing.time_compile_problem
2.32±0.06s 2.26±0.02s 0.97 gini_portfolio.Cajas.time_compile_problem
121±4ms 118±0.3ms 0.97 high_dim_convex_plasticity.ConvexPlasticity.time_compile_problem
15.8±0.2s 15.1±0.08s 0.95 finance.CVaRBenchmark.time_compile_problem
1.60±0.06s 1.52±0.01s 0.95 gini_portfolio.Murray.time_compile_problem

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.

2 participants