Summary
When a plugin fails to load, the failure is effectively invisible to the user. The error is captured and logged, but never surfaced in a way anyone would notice — so a broken plugin looks indistinguishable from a plugin that loaded and simply isn't responding.
Surfaced while building the Vim compatibility layer (#386), where a genuine compile failure cost significant debugging time precisely because nothing told us the plugin hadn't loaded.
Current behavior
Plugin.Init() captures a load error into p.LastError and logs it to slog (internal/plugin/plugin.go:28-32), then returns. But:
- No notification is shown at startup when a plugin fails to load.
- The only user-facing signal is the "Installed Plugins" dialog, which renders the status as the bare word
error (internal/app/commands_plugin.go:109) — the actual message never reaches the user.
- Because
key.press listener errors are also swallowed at dispatch (internal/plugin/plugin.go, DispatchKeyEvent), a plugin that loaded but throws mid-handler is also silent, and looks identical to "didn't load."
Net effect: a broken plugin presents as "my keys do nothing" with no breadcrumb pointing at the plugin, let alone the reason.
Why it matters
Real failure modes that are currently silent:
- gopher-lua's 200-live-locals-per-scope limit (Lua 5.1). Verified: a scope with 201 locals fails to compile with
too many local variables. A large plugin's main chunk hits this; the workaround is do ... end blocks, but nothing tells the author that's the problem.
- Any syntax error,
nil call, or bad require at load time.
- Any error thrown inside a
key.press (or other event) listener at runtime.
Every one of these currently reads as "the plugin silently doesn't work."
Proposed changes
- Surface load failures at startup — a notification such as
Plugin 'vim' failed to load — see Installed Plugins when Init() returns an error during Manager.LoadAll.
- Show the actual message in the Installed Plugins dialog — display
p.LastError text (or a truncated form) next to the error status, not just the word error.
- Consider surfacing swallowed listener errors — e.g. rate-limited notification, or at least a visible indicator, the first time an event listener throws, so a runtime error in a handler isn't indistinguishable from a no-op.
Also worth documenting (docs, cheaper)
The gopher-lua constraints that make silent failure so likely are not written down for plugin authors. Add to plugin-authoring.md:
- gopher-lua is Lua 5.1: no
%g, no goto, no //, no utf8 library.
- 200 live locals per scope; use
do ... end blocks to release registers in large plugins.
- Multi-file plugins are not supported (the sandbox strips
package.loaders).
- gopher-lua codegen bug: multiple assignment is not simultaneous for local variables —
local a,b = b,a yields b,b (table-field targets are fine). Use an explicit temporary.
The doc portion will land alongside #386's plugin-authoring updates; this issue tracks the not-silent behavior change.
Summary
When a plugin fails to load, the failure is effectively invisible to the user. The error is captured and logged, but never surfaced in a way anyone would notice — so a broken plugin looks indistinguishable from a plugin that loaded and simply isn't responding.
Surfaced while building the Vim compatibility layer (#386), where a genuine compile failure cost significant debugging time precisely because nothing told us the plugin hadn't loaded.
Current behavior
Plugin.Init()captures a load error intop.LastErrorand logs it to slog (internal/plugin/plugin.go:28-32), then returns. But:error(internal/app/commands_plugin.go:109) — the actual message never reaches the user.key.presslistener errors are also swallowed at dispatch (internal/plugin/plugin.go, DispatchKeyEvent), a plugin that loaded but throws mid-handler is also silent, and looks identical to "didn't load."Net effect: a broken plugin presents as "my keys do nothing" with no breadcrumb pointing at the plugin, let alone the reason.
Why it matters
Real failure modes that are currently silent:
too many local variables. A large plugin's main chunk hits this; the workaround isdo ... endblocks, but nothing tells the author that's the problem.nilcall, or badrequireat load time.key.press(or other event) listener at runtime.Every one of these currently reads as "the plugin silently doesn't work."
Proposed changes
Plugin 'vim' failed to load — see Installed PluginswhenInit()returns an error duringManager.LoadAll.p.LastErrortext (or a truncated form) next to theerrorstatus, not just the worderror.Also worth documenting (docs, cheaper)
The gopher-lua constraints that make silent failure so likely are not written down for plugin authors. Add to
plugin-authoring.md:%g, nogoto, no//, noutf8library.do ... endblocks to release registers in large plugins.package.loaders).local a,b = b,ayieldsb,b(table-field targets are fine). Use an explicit temporary.The doc portion will land alongside #386's plugin-authoring updates; this issue tracks the not-silent behavior change.