         return not @save_button.hasClass('disabled')
 
     save: (cb) =>
-        if not @nb? or @readonly
+        if not @nb? or @readonly or not @doc?
             cb?(); return
         @save_button.icon_spin(start:true, delay:4000)
         @nb.save_notebook?(false)

                            if not require('./feature').IS_MOBILE
                                @frame.$("#site").css("padding-left", "20px")

                            ### -- WARNING: this code below completely breaks everything on Firefox!
                            @nb._save_checkpoint = @nb.save_checkpoint
                            @nb.save_checkpoint = @save
                            ###

                            # We have our own auto-save system
                            @nb.set_autosave_interval(0)


        @con      = @element.find(".smc-jupyter-notebook-connecting")
        @setup () =>
            # TODO: We have to do this stupid thing because in IPython's notebook.js they don't systematically use
            # set_dirty, sometimes instead just directly setting the flag.  So there's no simple way to know exactly
            # when the notebook is dirty. (TODO: fix all this via upstream patches.)

            @_autosync_interval = setInterval(@autosync, @opts.sync_interval)
            @_cursor_interval   = setInterval(@broadcast_cursor_pos, @opts.cursor_interval)
