Skip to content

[BUG] Keybindings: "unknown keybinding action" log flood on every chat launch #722

Description

@edenreich

Summary

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

  1. Generate a fresh config: infer init (writes ~/.infer/keybindings.yaml with the default bindings).
  2. Launch and quit the chat TUI: infer chat.
  3. Inspect the day's log:
    • grep -c "unknown keybinding action" ~/.infer/logs/app-$(date +%F).log
    • grep -c "Ignored key without a value" ~/.infer/logs/app-$(date +%F).log

Expected Behavior

A stock config produces zero unknown 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:

  1. 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.go getValidActionIDs() shares the blind spot, so infer keybindings validate
    lists the same bogus IDs.

  2. 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.

  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingreleased

    Type

    Fields

    No fields configured for Bug.

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions