First, your error message. It's surprising, but fairly clear. Your note about the problematic axes being the only 3d one is the key. Two minimal examples with and without the error:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.widgets as widgets
hf1,ha1 = plt.subplots()
ha1.plot([1,2,3],[4,5,6])
butt1 = widgets.Button(ha1,'button 1') # <-- works great
hf2 = plt.figure()
ha2 = hf2.add_subplot(111,projection='3d')
ha2.plot([1,2,3],[4,5,6],[7,8,9])
butt2 = widgets.Button(ha2,'button 2') # <-- error
First, a look at /usr/local/lib/python3.4/dist-packages/matplotlibwidgets.py, around line 191:
class Button(AxesWidget):
def __init__(self, ax, label, image=None,
color='0.85', hovercolor='0.95'):
AxesWidget.__init__(self, ax)
if image is not None:
ax.imshow(image)
self.label = ax.text(0.5, 0.5, label,
verticalalignment='center',
horizontalalignment='center',
transform=ax.transAxes) # <-- line 191
The button attempts to call the text method of the Axes it's being put into, and this call is producing the error. With the help of ha1.text (bound version of matplotlib.pyplot.Axes.text):
text(x, y, s, fontdict=None, withdash=False, **kwargs) method of matplotlib.axes._subplots.AxesSubplot instance
Add text to the axes.
Add text in string `s` to axis at location `x`, `y`, data
coordinates.
The same for ha2.text (bound version of mpl_toolkits.mplot3d.Axes3D.text):
text(x, y, z, s, zdir=None, **kwargs) method of matplotlib.axes._subplots.Axes3DSubplot instance
Add text to the plot. kwargs will be passed on to Axes.text,
except for the `zdir` keyword, which sets the direction to be
used as the z direction.
Spot the difference: the latter function has to receive a z coordinate as well in order to place the text on the 3d axes. Makes sense. The Button widget is simply not designed to work with 3d axes.
Now, you could try hacking yourself around the problem, although the fact that Button is clearly lacking 3d axes support suggests that you will sooner or later shoot yourself in the foot. Anyway, you can actually get rid of the error by overwriting the text method of ha2 with that of ha1 with some adjustments to put self in the right place. Again, I'm not saying that this can't break anything anytime, nor that it's something horrible to do, but it's an option:
hf2 = plt.figure()
ha2 = hf2.add_subplot(111,projection='3d')
ha2.plot([1,2,3],[4,5,6],[7,8,9])
ha2.text = lambda x,y,s,self=ha2,**kwargs : plt.Axes.text(self,x,y,s,kwargs)
butt2 = widgets.Button(ha2,'button 2') # <-- no error
For what it's worth, it now looks as bad as the 2d version:

This leads me to my final point. As far as I can tell, widgets automatically occupy the entire axes they're put into. And it seems reasonable to not put a widget (an inherently 2d object) into a 3d axes: how exactly do you want it to be positioned? The obvious solution would be to store each widget in its own axes, on top of/next to the other GUI components and figures. This way you can naturally use 2d axes for each widget. I believe this is the standard approach for doing this, which might explain why there's no explicit mention of 3d axes not being supported. Why would they be?