{"record":{"id":"c3e13a6dc9f41048","repo":"jashkenas/backbone","slug":"backbone-history-has-already-been-started","errorCode":null,"errorMessage":"Backbone.history has already been started","messagePattern":"Backbone\\.history has already been started","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"backbone.js","lineNumber":1880,"sourceCode":"      return path.charAt(0) === '/' ? path.slice(1) : path;\n    },\n\n    // Get the cross-browser normalized URL fragment from the path or hash.\n    getFragment: function(fragment) {\n      if (fragment == null) {\n        if (this._usePushState || !this._wantsHashChange) {\n          fragment = this.getPath();\n        } else {\n          fragment = this.getHash();\n        }\n      }\n      return fragment.replace(routeStripper, '');\n    },\n\n    // Start the hash change handling, returning `true` if the current URL matches\n    // an existing route, and `false` otherwise.\n    start: function(options) {\n      if (History.started) throw new Error('Backbone.history has already been started');\n      History.started = true;\n\n      // Figure out the initial configuration. Do we need an iframe?\n      // Is pushState desired ... is it available?\n      this.options          = _.extend({root: '/'}, this.options, options);\n      this.root             = this.options.root;\n      this._trailingSlash   = this.options.trailingSlash;\n      this._wantsHashChange = this.options.hashChange !== false;\n      this._hasHashChange   = 'onhashchange' in window && (document.documentMode === void 0 || document.documentMode > 7);\n      this._useHashChange   = this._wantsHashChange && this._hasHashChange;\n      this._wantsPushState  = !!this.options.pushState;\n      this._hasPushState    = !!(this.history && this.history.pushState);\n      this._usePushState    = this._wantsPushState && this._hasPushState;\n      this.fragment         = this.getFragment();\n\n      // Normalize root to always include a leading and trailing slash.\n      this.root = ('/' + this.root + '/').replace(rootStripper, '/');\n","sourceCodeStart":1862,"sourceCodeEnd":1898,"githubUrl":"https://github.com/jashkenas/backbone/blob/f229c75b194a63a8e07a3313ce43e8d2dc105327/backbone.js#L1862-L1898","documentation":"Backbone.History.start() initializes client-side routing (hashchange/pushState listening), and History.started is a global flag. Starting it twice would register duplicate listeners and re-initialize routing state, so Backbone guards with this explicit error. Only one history instance should ever be started per page load.","triggerScenarios":"Calling Backbone.history.start() (or a History subclass instance's start()) more than once in the same page — e.g., calling it both in app bootstrap code and again in a router initialization or an AJAX-complete callback, or re-running a bootstrap script on route change.","commonSituations":"Duplicated bootstrap code (require/AMD module loaded twice, script included twice); legacy code paths that re-call start() after navigation; frameworks wrapping Backbone that call start() internally while app code also calls it; hot-reload setups re-executing initialization modules.","solutions":["Guard the call: if (!Backbone.History.started) Backbone.history.start();","Move start() to a single, top-level entry point and remove duplicate invocations.","Track your own initialized flag around your bootstrap function so it runs only once.","Ensure the bootstrap script/module isn't loaded or evaluated twice (check script tags and module loading)."],"exampleFix":"// before\nBackbone.history.start();\n// ...later, possibly again:\nBackbone.history.start(); // throws\n\n// after\nif (!Backbone.History.started) {\n  Backbone.history.start({pushState: true});\n}","handlingStrategy":"validation","validationCode":"if (!Backbone.History.started) {\n  Backbone.history.start({pushState: true, root: '/'});\n}","typeGuard":null,"tryCatchPattern":"try {\n  Backbone.history.start();\n} catch (e) {\n  if (e.message !== 'Backbone.history has already been started') throw e;\n  // already started: safe to ignore\n}","preventionTips":["Call Backbone.history.start() exactly once, in a single bootstrap module.","Use the Backbone.History.started flag as a guard before any start() call.","Check for duplicate script tags or double module evaluation in your bundler config.","If a wrapper framework may have started routing, rely on its lifecycle instead of calling start() again.","In tests/hot-reload, fully tear down or reload the page between history starts."],"tags":["backbone","router","history","initialization"],"backgroundTag":"already-initialized","analyzedSha":"f229c75b194a63a8e07a3313ce43e8d2dc105327","analyzedAt":"2026-08-28T23:02:54.813Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}