It would be "nice" if these local solvers (e.g., fmincon, snopt, knitro) were finding a local optimum (minimum). Instead, they are starting from default starting value of zeros(n,1), checking the first order optimality conditions, seeing that they are met within tolerance, and declaring a locally optimal solution has been found; when in fact they have "found" the global maximum (the worst possible point) rather than a local minimum. They incorrectly declare victory, without even trying.
In this case, using a starting point, such as 1e-6*ones(n,1), such that first order optimality conditions are not met within tolerance there, is sufficient to get the solver really doing something, and then they find a true locally optimal solution, which in this case happens to be globally optimal. This is also true with Johan's alternate formulation (except that using the default starting value of zeros(n,1), ipopt declares victory without even trying on Johan's formulation, but tries and fails on the original formulation).