Troubleshooting
A short tour through the most common ways Logaria can surprise you — and the answer in each case.
"Cannot call setLoggerConfig() under plugin control"
Symptom
Error: logaria is controlled by loggerPlugin.vite({ config }). setLoggerConfig(...) and
resetLoggerConfig() cannot be used in this runtime; update the loggerPlugin.vite({ config })
option in your bundler config instead.Why — You installed loggerPlugin in your bundler. The default scope is now controlled by the build constants the plugin injects, and the runtime APIs refuse to mutate it.
Fix — Edit the plugin config option in your bundler config:
loggerPlugin.vite({
config: {
levels: ['warn', 'error'],
},
});This applies to every adapter, not just Vite — the error message names the adapter you used. See Runtime Config — Controlled Runtime.
Missing Scope ID
Symptom
Error: Logger config for scope "..." is not registered in this runtime. Call
setScopedLoggerConfig(scopeId, config) before creating a scoped logger.Why — You called createScopedLogger(options, scopeId) before registering that scope.
Fix — Register the scope first:
import { createScopedLogger, setScopedLoggerConfig } from 'logaria/core';
setScopedLoggerConfig(scopeId, {
levels: ['warn', 'error'],
});
const logger = createScopedLogger({ main: '@acme/host' }, scopeId).getLoggerByGroup('build');Empty scope ids
An empty or whitespace-only string normalizes to the default scope id, which is rarely what you want. Always use createLoggerScopeId() or a non-empty stable string.
Rules Silently Drop Everything
Symptom — You added a rules block, and now nothing prints — not even errors that should obviously match.
Why — Once at least one rule resolves, Logaria switches to rule mode: unmatched logs are dropped and do not fall back to root levels.
Fix options
- Verify your rule matches:
mainis exact,groupandmessageare exact unless they contain glob characters. - Use
levels: 'inherit'on a catch-all rule to keep rootlevelsbehaviour for other logs:
setLoggerConfig({
levels: ['warn', 'error'],
rules: {
'custom:catch-all': {
levels: 'inherit',
},
'custom:metrics': {
group: 'userland.metrics',
message: '*timeout*',
levels: ['info', 'warn'],
},
},
});See Rules & Presets for full semantics.
Glob Behaves Like Exact (or Vice Versa)
Symptom — A rule like group: 'api.users' does not match api.users.detail, or group: 'api.*' matches api.users but not api.
Why — Logaria upgrades a string to glob matching only when it contains glob characters (*, ?, [a-z], {a,b}). Otherwise it is an exact equality match.
Fix
- For prefix-style matching, use
api.*orapi.**. - For one-of, use
{login,logout,refresh}. - For exact, drop the glob characters.
logger.debug() Never Prints
Symptom — debug calls are completely silent even though info works.
Why — Two independent reasons, either of which hides debug():
debugis controlled by thedebugflag, not thelevelslist. By defaultdebug: false, so debug output is hidden.- You are in rule mode. Once any rule resolves,
logger.debug()is always suppressed — even withdebug: true. Debug calls print only in level mode (no rules configured).
Fix — In level mode, set debug: true:
setLoggerConfig({
debug: true,
levels: ['info', 'success', 'warn', 'error'],
});If you need debug() output, make sure no rules are configured — in rule mode, debug calls never print. Under plugin control, set the same flag through your adapter, e.g. loggerPlugin.vite({ config: { debug: true } }).
Tree-Shaking Did Not Remove a Call
Symptom — You enabled treeshake: true but a log call still appears in the production bundle.
Why — Pruning is intentionally conservative. A call is removed only when every static fact holds. Common reasons one fails:
createLoggerwas imported with an alias (import { createLogger as cl } from 'logaria').main,group, or the message is a template literal, variable, or computed expression rather than a string literal.- The logger binding was reassigned.
- A method was destructured (
const { info } = logger) or accessed via computed key (logger['info']). - The log call is not a standalone expression (e.g. its result is assigned).
- The bundler is in dev or watch mode — pruning only runs in build mode.
Fix — Adjust the call site to fit the supported static shape, or accept that runtime filtering is doing its job and the call stays.
@rollup/plugin-replace Not Installed
Symptom
Error: Failed to import module "@rollup/plugin-replace". Please ensure it is installed.Why — loggerPlugin.rollup(...) requires @rollup/plugin-replace as a peer dependency; other adapters use their bundler's native define hook and do not need it.
Fix
pnpm add -D @rollup/plugin-replaceLogs Print in Tests Across Files
Symptom — A setLoggerConfig call in one test changes the default scope and bleeds into the next test.
Why — The default scope is process-global. Mutating it from one test affects every other test running in the same worker.
Fix — Pair every setLoggerConfig call with resetLoggerConfig:
afterEach(() => {
resetLoggerConfig();
});For tests that need their own visibility policy without touching the default scope, use a scoped integration and a generated scopeId.
rules Must Be an Object Map
Symptom
Error: logger.rules must be an object map, not an array.Why — rules is keyed by label, not a list. It is easy to reach for an array — the test spec describes rules as a numbered list of resolved shapes — but the public config is an object map.
Fix — Key each rule by its label:
setLoggerConfig({
levels: ['warn', 'error'],
rules: {
'custom:metrics': {
group: 'userland.metrics',
levels: ['info', 'warn'],
},
},
});Each value is 'off' or a rule object, and every rule object must declare levels. See Rules & Presets.
Still Stuck?
If a behaviour does not match anything on this page, please open an issue with:
- The Logaria version (
npm ls logaria). - A minimal repro — config shape and a single call site is usually enough.
- Whether the issue reproduces with
loggerPlugininstalled or only with the root runtime.