angular/angular.js · error · Error
Expected $log to be empty! Either a message was logged unexp
Error message
Expected $log to be empty! Either a message was logged unexpectedly, or an expected log message was not checked and removed:
What it means
The $log mock records every call to error/warn/info/log/debug in per-level arrays. $log.assertEmpty() throws if any level collected messages, joining each entry (with its stack) under the header 'Expected $log to be empty!'. It is a test assertion that no component — yours or Angular's — logged unexpectedly during the spec.
Source
Thrown at src/ngMock/angular-mocks.js:556
* @description
* Assert that all of the logging methods have no logged messages. If any messages are present,
* an exception is thrown.
*/
$log.assertEmpty = function() {
var errors = [];
angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) {
angular.forEach($log[logLevel].logs, function(log) {
angular.forEach(log, function(logItem) {
errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' +
(logItem.stack || ''));
});
});
});
if (errors.length) {
errors.unshift('Expected $log to be empty! Either a message was logged unexpectedly, or ' +
'an expected log message was not checked and removed:');
errors.push('');
throw new Error(errors.join('\n---------\n'));
}
};
$log.reset();
return $log;
};
};
/**
* @ngdoc service
* @name $interval
*
* @description
* Mock implementation of the $interval service.
*
* Use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
* move forward by `millis` milliseconds and trigger any functions scheduled to run in thatView on GitHub (pinned to d8f77817eb)
Solutions
- Fix the root cause: make the code (or the mocked responses) not produce the logged message.
- If the message is expected, assert it explicitly ($log.error.logs[0][0]) and then call $log.reset() before assertEmpty runs.
- Call $log.reset() in tests that intentionally exercise error paths so recorded entries do not leak into a later assertEmpty.
Example fix
// before
it('handles 500', inject(function($httpBackend, $http, $log) {
$httpBackend.expectGET('/api').respond(500, 'boom');
$http.get('/api');
$httpBackend.flush();
$log.assertEmpty(); // throws: $http logged the 500
}));
// after
it('handles 500', inject(function($httpBackend, $http, $log) {
$httpBackend.expectGET('/api').respond(500, 'boom');
$http.get('/api');
$httpBackend.flush();
expect($log.error.logs.length).toBe(1); // assert it, then clear
$log.reset();
})); Defensive patterns
Strategy: validation
Validate before calling
// Check recorded logs yourself before asserting emptiness
function logLevelsEmpty($log) {
return ['error', 'warn', 'info', 'log', 'debug'].every(function(level) {
return $log[level].logs.length === 0;
});
}
if (!logLevelsEmpty($log)) {
// assert/clear specific entries first, then $log.reset()
} Try / catch
// Let assertEmpty run, but surface the entries it collected on failure
try {
$log.assertEmpty();
} catch (e) {
// e.message already contains each MOCK $log line + stack; rethrow with spec name
throw new Error(specName + ' failed assertEmpty:\n' + e.message);
} Prevention
- Call $log.reset() after asserting expected messages, and in tests that intentionally log.
- Make mocked error responses (4xx/5xx) deliberate: either assert the $log entry or avoid the error path.
When it happens
Trigger: Any $log.error/warn/info/log/debug call during the test followed by $log.assertEmpty(): a $http request answered with a 4xx/5xx status by the mock backend; a rejected $q promise logged by code under test; ngRoute/ngMessages/UI-Router deprecation or interpolation warnings; stack traces are included because logItem.stack is appended.
Common situations: afterEach($log.assertEmpty) added to keep tests clean, then failing because a mocked endpoint returns an error status and $http logs it; a third-party module logs a one-time warning on first digest; an expected error is logged (the test wanted it) but assertEmpty still treats it as a failure because reading logs does not clear them.
Related errors
- No deferred tasks to be flushed
- Deferred tasks to flush ({}): {}
- Unknown mode '{}', only 'log'/'rethrow' modes are allowed!
- No pending animations ready to be closed or flushed
- No pending request to flush !
AI-assisted analysis of angular/angular.js@d8f77817eb (2026-08-21).
Data as JSON: /api/errors/25643e1ea8749d20.
Report an issue: GitHub.