{"action":"closed","issue":{"url":"https://api.github.com/repos/angular-ui/ui-router/issues/898","labels_url":"https://api.github.com/repos/angular-ui/ui-router/issues/898/labels{/name}","comments_url":"https://api.github.com/repos/angular-ui/ui-router/issues/898/comments","events_url":"https://api.github.com/repos/angular-ui/ui-router/issues/898/events","html_url":"https://github.com/angular-ui/ui-router/issues/898","id":27782753,"number":898,"title":"Infinite loop when redirecting to state from $stateChangeError handler","user":{"login":"albv","id":1935832,"avatar_url":"https://avatars.githubusercontent.com/u/1935832?v=3","gravatar_id":"","url":"https://api.github.com/users/albv","html_url":"https://github.com/albv","followers_url":"https://api.github.com/users/albv/followers","following_url":"https://api.github.com/users/albv/following{/other_user}","gists_url":"https://api.github.com/users/albv/gists{/gist_id}","starred_url":"https://api.github.com/users/albv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/albv/subscriptions","organizations_url":"https://api.github.com/users/albv/orgs","repos_url":"https://api.github.com/users/albv/repos","events_url":"https://api.github.com/users/albv/events{/privacy}","received_events_url":"https://api.github.com/users/albv/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":13,"created_at":"2014-02-18T10:19:50Z","updated_at":"2015-09-11T22:24:28Z","closed_at":"2015-09-11T22:24:27Z","body":"Here is a minimal example I made to reproduce my issue:\r\n```\r\nangular.module('routerTestApp', ['ui.router'])\r\n\r\n    .config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {\r\n\r\n        $urlRouterProvider.otherwise('/state/a');\r\n\r\n        $stateProvider.\r\n            state('state', {\r\n                url: '/state',\r\n                abstract: true,\r\n                resolve: {\r\n                    parentResolved: ['$timeout', function ($timeout) {\r\n                        return $timeout(function () {\r\n                            return [];\r\n                        }, 1000);\r\n                    }]\r\n                }\r\n            }).\r\n\r\n            state('state.a', {\r\n                url: '/a',\r\n                resolve: {\r\n                    resolved: ['$q', 'parentResolved', function ($q, parentResolved) {\r\n                        return $q.reject({ redirect: 'state.b' });\r\n                    }]\r\n                }\r\n            }).\r\n\r\n            state('state.b', {\r\n                url: '/b'\r\n            });\r\n\r\n    }])\r\n\r\n    .run(['$rootScope', '$exceptionHandler', '$state', function ($rootScope, $exceptionHandler, $state) {\r\n        $rootScope.$on('$stateChangeError', function (e, toState, toParams, fromState, fromParams, error) {\r\n            if (error && error.redirect) {\r\n                return $state.go(error.redirect);\r\n            }\r\n\r\n            $exceptionHandler(error);\r\n        });\r\n    }]);\r\n```\r\nThe problem is when going to any non-existent url such as '/abc' for example - app falls to infinite 'location change' loop. Url should be pasted directly to browser address string because if previously we entered some valid state all subsequent redirects would work as expected.\r\n\r\nBy 'location change' loop I mean following:\r\n1)  $urlRouterProvider.otherwise('/state/a') send us to 'state.a'\r\n2) 'state.a' resolve failed so $stateChangeError handler is called\r\n3) handler redirects us to 'state.b'\r\n4) but syncUrl() function that called in ui-router after firing $stateChangeError sees that currentLocation (it's '/abc' at that moment) doesn't match $location.url() and sends us back to '/abc' - so we are returning to point 1).\r\n"}}