2026, Jan 07 11:00

Debugging SLSQP Constraints in SciPy: fix ValueError from mixing 1D vectors with 2D arrays

Learn why SLSQP in scipy.optimize throws ValueError when constraints return 2D arrays, and how to fix it by returning scalars or 1D vectors. Debug steps inside.

Debugging SLSQP constraints in scipy.optimize can be counterintuitive when shape mismatches sneak into constraint outputs. A common pitfall is mixing scalars/1D arrays with 2D arrays in different constraints, which surfaces as a ValueError deep inside SciPy. The fix is simple once you confirm what each constraint actually returns.

Repro: when one constraint returns 1D and another returns 2D

The error appears when at least one constraint returns a matrix (2D array) while others return a scalar or a 1D array. SLSQP expects each constraint function to return a scalar or a 1D array; anything 2D breaks the concatenation logic inside SciPy.

import numpy as np
from scipy.optimize import minimize

# Objective (arbitrary for illustration)
def obj_fn(vec):
    return (vec[0] - 2.0)**2

# First constraint: OK (scalar)
def c1(v):
    return v[0] - 1.0

# Second constraint: NOT OK (2D array)
def c2(v):
    # Returns shape (1, 2), which is 2D and will trigger the error
    return np.array([[v[0] - 0.5, v[0] - 0.2]])

start = np.array([0.0])
cons_bad = (
    {"type": "ineq", "fun": c1},
    {"type": "ineq", "fun": c2},
)

# This will raise the ValueError about mismatched dimensions
minimize(obj_fn, start, method="SLSQP", constraints=cons_bad)

What’s really happening

Inside SLSQP, SciPy evaluates your constraints and stacks their outputs together. It coerces each constraint’s return via atleast_1d and then attempts to concatenate them. If one constraint yields a scalar or a 1D array and another yields a 2D array, NumPy refuses to concatenate because the input arrays don’t share the same dimensionality. That is the direct cause of the error.

Crucially, constraint functions must return either a scalar or a 1D array. If any constraint returns a matrix, SLSQP will fail before it even gets to the optimization proper.

Fix: ensure every constraint returns a scalar or a 1D array

Audit each constraint and confirm the shape of its output. If any constraint computes a matrix, flatten or construct it as a 1D array. The simplest way is to return a 1D np.array([...]) or to use ravel() to collapse to 1D when that matches your intent.

import numpy as np
from scipy.optimize import minimize

# Objective unchanged
def obj_fn(vec):
    return (vec[0] - 2.0)**2

# First constraint: OK (scalar)
def c1(v):
    return v[0] - 1.0

# Second constraint: FIXED (1D array)
def c2_fixed(v):
    # Return a flat 1D array instead of a 2D matrix
    return np.array([v[0] - 0.5, v[0] - 0.2])

start = np.array([0.0])
cons_ok = (
    {"type": "ineq", "fun": c1},
    {"type": "ineq", "fun": c2_fixed},
)

# This now runs without the shape error
minimize(obj_fn, start, method="SLSQP", constraints=cons_ok)

How to pinpoint the offending constraint

Print the shape of each constraint output right inside the constraint functions. For example, add a quick debug line like print("c2 shape:", np.shape(ret)) just before the return, or print(type(ret), np.asarray(ret).shape). This immediately shows you which one is returning a 2D array. You can also step through with pdb; Python’s built-in debugger can set breakpoints inside libraries if you need to follow the call into SciPy. As a last resort, temporarily instrument the relevant internals with simple print calls to see the types and shapes being concatenated.

Why this matters

Constraint shape mismatches are easy to overlook because NumPy silently promotes many structures until a deeper operation (like concatenation) enforces strict compatibility. Getting constraint outputs into a consistent, explicit shape eliminates a class of hard-to-locate errors and keeps the optimization path clear.

Takeaways

Keep every SLSQP constraint returning a scalar or a 1D array. If you have multiple inequalities from one function, return a flat vector, not a matrix. When troubleshooting, print or inspect the shapes at the constraint boundaries, and use pdb if needed. Once outputs are consistent, the ValueError disappears and you can focus on the actual optimization behavior rather than plumbing issues.