Files
LiveWall/docs/plugins/troubleshooting.md
T
2026-11-04 14:29:22 -06:00

6.1 KiB

Troubleshooting

First stop: the log

Everything is in %APPDATA%\LiveWall\logs\livewall-YYYYMMDD.log. Plugin lines are prefixed with the plugin id:

[com.example.clock] Clock plugin starting (plugin API 1.0, host 1.8.0)
[plugins] loaded com.example.clock v1.0.0 (sha256 3f8c…, verified)

Also useful:

  • Plugins ▸ Plugin log — in-app summary: every plugin, its state, hash, permissions, overlays, pages, commands, filters, renderers.
  • Advanced ▸ Diagnostics — the same report inside the full diagnostics dump, plus the engine state.
  • Advanced ▸ Open log folder.

The plugin does not appear in the list

Symptom Cause Fix
Folder listed but named after the folder plugin.json missing or unparsable Fix the JSON; the row says Invalid manifest: …
Nothing at all Wrong folder Must be %APPDATA%\LiveWall\plugins\<something>\plugin.json, not plugins\plugin.json
Nothing at all Plugin system off Plugins ▸ Enable the plugin system (warning required)
Appears, greyed state Incompatible apiVersion major mismatch or minHostVersion too new Update the plugin, or lower minHostVersion
Appears, Rejected checksum in the manifest does not match the DLL Rebuild, or clear checksum
Appears, Failed Assembly/type problem, or Initialize threw Read the state message; fix the type name or the exception
Appears, NotApproved Loaded and ready, waiting for the user Press Enable and accept the warning

Enable does nothing / warning reappears every time

  • "allow unverified plugins" is off and the plugin is unverified → turn that option on (in the Plugin system card) or use a build whose hash you approved before.
  • The hash changes on every build (normal). Approving a build approves that binary; rebuild and you are asked again. During development, leave Allow unverified on and keep an eye on the log rather than re-approving each time.
  • A Forget trust click clears the stored hash — that is what it does.

"Could not load file or assembly … LiveWall.Sdk"

The plugin was built with an incompatible SDK, or it shipped its own LiveWall.Sdk.dll. Delete the copy from the plugin folder and reference the SDK with <Private>false</Private>.

"Cannot cast … to ILiveWallPlugin"

Same cause: a second copy of the contract assembly. The plugin's ILiveWallPlugin came from a different assembly identity than the host's.

Overlay does not show up

  1. Is the plugin Active and does the log mention overlay registered?
  2. Is the desktop icon window alive? LiveWall creates the overlay host window even with desktop icons disabled, but a third-party shell replacement (StartAllBack, ExplorerPatcher) can break WorkerW — press Re-attach on the Display tab.
  3. Did you return a FrameworkElement with a size? A StackPanel with no children is invisible.
  4. Is it behind the icons by design? The overlay sits above the wallpaper and below the icons; text in the top-right corner is a safe place to test.
  5. Did you call OnVisibilityChanged correctly? LiveWall calls it with false when overlays are hidden (tray Hide overlay), so a timer you stopped there must be restarted on true.

Clicks on my overlay do nothing

Expected. The overlay layer is IsHitTestVisible = false: clicks must reach the desktop icons. If you need interaction, that is a renderer feature (renderers live in the wallpaper window and can be made interactive with InteractiveMode), not an overlay feature.

Settings page is blank

CreateView threw. The exception is shown in the page and logged. The usual culprit is referencing LiveWall.Themes resources by key that does not exist — the safe keys are BgWindow, BgCard, BgField, BgHover, BorderBrushSoft, TextBrush, TextDim, AccentBrush, AccentSoft, GreenBrush, DangerBrush, and the styles Card, Hint, SectionTitle, PageTitle, AccentButton, GhostButton, TinyButton, Label, Mono.

Hotkey does nothing

  • Another app (or LiveWall itself) already owns the combination — the log says so.
  • Gesture syntax: modifiers first (Ctrl+Alt+K), one key. Ctrl+Shift+3 is not valid, Ctrl+Shift+D3 is.
  • The Hotkeys permission must be declared.

Filter breaks wallpaper changes

Filters run before the engine applies a request, including requests from playlists and other plugins. A filter that always returns a fixed request effectively pins the wallpaper (that is the point of the sample's Pin wallpaper option). Exceptions inside Apply disable your filter for that pass and are logged; they do not disable the plugin.

Renderer never gets used

  • CanRender must return true for the request the engine actually sees — after filters. Log what you receive.
  • Another plugin with a higher Priority claimed it first. Priorities are per plugin; the first true wins.
  • The Renderer permission must be declared, otherwise AddRenderer is refused.
  • After a source change LiveWall calls Create once and Load per source. If Load throws, the message appears in the status line and the plugin is not retried for that source.

Unloading

LiveWall unloads a plugin when it is disabled, rescanned, or when the app exits. The collectible load context only actually releases the assembly if nothing keeps a reference alive:

  • unsubscribe every IDisposable you got from Events.Subscribe in Shutdown;
  • stop and unhook DispatcherTimers, System.Timers.Timers, FileSystemWatchers;
  • do not keep static references in the host's types to your objects (a static in a host-owned class is fine only if it lives in your assembly);
  • do not leave Tasks running: observe context.ShutdownToken.

If a plugin stays "loaded" after Disable, the log says unload deferred — restart LiveWall to finish the job. This is a leak in the plugin, not in LiveWall.

Reporting a bug

Include: LiveWall version, plugin id + version + hash (from the warning dialog or Plugin log), the relevant log excerpt, and the exact steps. If the app crashed, the last lines of the log before the crash are usually enough to identify the plugin.