I'll go ahead and answer this one myself. After a lot of crashes, I searched down the crash string and it lead me to this file on the mozilla development network for the mariontte.py
Looking through the code I saw these lines
@do_process_check
def quit(self, in_app=False):
"""Terminate the currently running instance.
This command will delete the active marionette session. It also allows
manipulation of eg. the profile data while the application is not running.
To start the application again, start_session() has to be called.
:param in_app: If True, marionette will cause a quit from within the
browser. Otherwise the browser will be quit immediately
by killing the process.
"""
if not self.instance:
raise errors.MarionetteException("quit() can only be called "
"on Gecko instances launched by Marionette")
I kept getting the crash quit() can only be called on Gecko instanced launched by Marionette
then I looked around and saw the force quit option so I tried that and it seems to kill the last Firefox window.
Maybe in the future Firefox team can fix this or I might be using the API wrong.
If you have more than 1 tab open you can close it by switching to that window handle and calling client.close() on that window handle.
If you only have one tab left open, that no longer works and for me I had to call
client._send_message("quitApplication", {"flags": ["eForceQuit"]})
to close the last window and exit.