You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The chat TUI writes a flood of unknown keybinding action warnings on every launch - about 84 log
lines per infer chat start (42 warn + 42 error) in ~/.infer/logs/app-<date>.log - even with a
pristine infer init config. The root cause is a validation mismatch: the runtime key registry treats a
whole class of legitimate, namespace-path actions (chat_focus_attachments, diff_viewer_*, explorer_*) as "unknown", compounded by a structured-logger misuse that turns each warning into two
lines (a warn with a literal, unexpanded %s plus a spurious zap error). None of this reaches the
screen, but it makes the log file useless for real debugging.
Steps to Reproduce
Generate a fresh config: infer init (writes ~/.infer/keybindings.yaml with the default bindings).
grep -c "Ignored key without a value" ~/.infer/logs/app-$(date +%F).log
Expected Behavior
A stock config produces zerounknown keybinding warnings. Only a genuinely unrecognized action ID
(a typo or a removed/renamed action) yields exactly one clean, structured warning that names the
offending action.
Actual Behavior
Every launch emits ~84 lines. Each unknown action produces two paired lines. The warn line has a
literal, unexpanded %s and does not name the action:
{"level":"warn","caller":"keybinding/registry.go:364","msg":"unknown keybinding action '%s' in config, ignoring"}
The action name instead leaks into a second, error-level line emitted by zap itself:
{"level":"error","caller":"logger/logger.go:113","msg":"Ignored key without a value.","ignored":"diff_viewer_discard"}
Root Cause
Three distinct issues combine:
Structural drift (the flood; affects every user).config.GetDefaultKeybindings() (what infer init writes) enumerates 81 action IDs. 41 of them - chat_focus_attachments, all 23 diff_viewer_*, and all 17 explorer_* - are intentionally never registered in the runtime Registry; they are consumed through a separate path, config.ResolveNamespaceBindings
(internal/app/chat.go, internal/ui/components/diff_viewer.go, internal/ui/components/file_explorer.go). But (*Registry).ApplyConfigOverrides
(internal/ui/keybinding/registry.go:352-378) iterates the whole config and warns for any ID absent
from its actions map, so it false-flags all 41 on every launch. The CLI validator cmd/keybindings.gogetValidActionIDs() shares the blind spot, so infer keybindings validate
lists the same bogus IDs.
Logger misuse (doubles the noise).registry.go:364 calls logger.Warn("unknown keybinding action '%s' in config, ignoring", actionID), but logger.Warn(msg, args...) (internal/logger/logger.go:110) forwards to zap's key-value sugared API
(sugar.Warnw). So %s is never expanded and the trailing actionID becomes a dangling structured
key with no value - which is why zap adds the extra error-level Ignored key without a value. line.
Stale rename (config drift).fix(plan): accepting a plan switches to auto-accept mode by default #714 renamed the plan_approval accept-and-auto-approve action;
older keybindings.yaml files still reference the old ID. After the fix this correctly produces one
accurate warning (it genuinely is unknown now).
Proposed Fix
Validate config action IDs against the union of registry-registered IDs and default-config IDs
(config.GetDefaultKeybindings() keys), matched by exact ID - so namespace-path actions stop
false-warning while real typos still warn.
Convert the log call to structured form: logger.Warn("unknown keybinding action in config, ignoring", "action", actionID).
Share the same "known IDs" set with the CLI validator in cmd/keybindings.go.
Environment
inference-gateway/cli, main branch.
Note: the printf-style structured-logger misuse in root cause (2) also appears at ~20 other call sites
across the codebase (same defect class, malformed log entries). That broader cleanup will be tracked in
a separate follow-up issue; this bug is scoped to the keybinding flood.
Summary
The chat TUI writes a flood of
unknown keybinding actionwarnings on every launch - about 84 loglines per
infer chatstart (42warn+ 42error) in~/.infer/logs/app-<date>.log- even with apristine
infer initconfig. The root cause is a validation mismatch: the runtime key registry treats awhole class of legitimate, namespace-path actions (
chat_focus_attachments,diff_viewer_*,explorer_*) as "unknown", compounded by a structured-logger misuse that turns each warning into twolines (a warn with a literal, unexpanded
%splus a spurious zaperror). None of this reaches thescreen, but it makes the log file useless for real debugging.
Steps to Reproduce
infer init(writes~/.infer/keybindings.yamlwith the default bindings).infer chat.grep -c "unknown keybinding action" ~/.infer/logs/app-$(date +%F).loggrep -c "Ignored key without a value" ~/.infer/logs/app-$(date +%F).logExpected Behavior
A stock config produces zero
unknown keybindingwarnings. Only a genuinely unrecognized action ID(a typo or a removed/renamed action) yields exactly one clean, structured warning that names the
offending action.
Actual Behavior
Every launch emits ~84 lines. Each unknown action produces two paired lines. The
warnline has aliteral, unexpanded
%sand does not name the action:{"level":"warn","caller":"keybinding/registry.go:364","msg":"unknown keybinding action '%s' in config, ignoring"}The action name instead leaks into a second,
error-level line emitted by zap itself:{"level":"error","caller":"logger/logger.go:113","msg":"Ignored key without a value.","ignored":"diff_viewer_discard"}Root Cause
Three distinct issues combine:
Structural drift (the flood; affects every user).
config.GetDefaultKeybindings()(whatinfer initwrites) enumerates 81 action IDs. 41 of them -chat_focus_attachments, all 23diff_viewer_*, and all 17explorer_*- are intentionally never registered in the runtimeRegistry; they are consumed through a separate path,config.ResolveNamespaceBindings(
internal/app/chat.go,internal/ui/components/diff_viewer.go,internal/ui/components/file_explorer.go). But(*Registry).ApplyConfigOverrides(
internal/ui/keybinding/registry.go:352-378) iterates the whole config and warns for any ID absentfrom its
actionsmap, so it false-flags all 41 on every launch. The CLI validatorcmd/keybindings.gogetValidActionIDs()shares the blind spot, soinfer keybindings validatelists the same bogus IDs.
Logger misuse (doubles the noise).
registry.go:364callslogger.Warn("unknown keybinding action '%s' in config, ignoring", actionID), butlogger.Warn(msg, args...)(internal/logger/logger.go:110) forwards to zap's key-value sugared API(
sugar.Warnw). So%sis never expanded and the trailingactionIDbecomes a dangling structuredkey with no value - which is why zap adds the extra
error-levelIgnored key without a value.line.Stale rename (config drift). fix(plan): accepting a plan switches to auto-accept mode by default #714 renamed the
plan_approvalaccept-and-auto-approve action;older
keybindings.yamlfiles still reference the old ID. After the fix this correctly produces oneaccurate warning (it genuinely is unknown now).
Proposed Fix
(
config.GetDefaultKeybindings()keys), matched by exact ID - so namespace-path actions stopfalse-warning while real typos still warn.
logger.Warn("unknown keybinding action in config, ignoring", "action", actionID).cmd/keybindings.go.Environment
inference-gateway/cli,mainbranch.across the codebase (same defect class, malformed log entries). That broader cleanup will be tracked in
a separate follow-up issue; this bug is scoped to the keybinding flood.