shadowsocks/shadowsocks-windows · error · Exception

{callbackName} not found

Error message

{callbackName} not found

What it means

Thrown by RegHotkeyFromString when HotkeyCallbacks.GetCallback(callbackName) returns null, meaning no handler has been registered in the HotkeyCallbacks registry under the supplied name. The method is meant to resolve a string callback name (e.g. "ShowLogsCallback") to a HotKeyCallBackHandler delegate. This fires before any hotkey is actually registered with the OS, so it is purely an internal lookup failure, not an OS-level registration error.

Source

Thrown at shadowsocks-csharp/Controller/HotkeyReg.cs:48

            }
            else
            {
                RegHotkeyFromString("", "SwitchSystemProxyCallback");
                RegHotkeyFromString("", "SwitchSystemProxyModeCallback");
                RegHotkeyFromString("", "SwitchAllowLanCallback");
                RegHotkeyFromString("", "ShowLogsCallback");
                RegHotkeyFromString("", "ServerMoveUpCallback");
                RegHotkeyFromString("", "ServerMoveDownCallback");
                MessageBox.Show(I18N.GetString("Register hotkey failed"), I18N.GetString("Shadowsocks"));
            }
        }

        public static bool RegHotkeyFromString(string hotkeyStr, string callbackName, Action<RegResult> onComplete = null)
        {
            var _callback = HotkeyCallbacks.GetCallback(callbackName);
            if (_callback == null)
            {
                throw new Exception($"{callbackName} not found");
            }

            var callback = _callback as HotKeys.HotKeyCallBackHandler;

            if (string.IsNullOrEmpty(hotkeyStr))
            {
                HotKeys.UnregExistingHotkey(callback);
                onComplete?.Invoke(RegResult.UnregSuccess);
                return true;
            }
            else
            {
                var hotkey = HotKeys.Str2HotKey(hotkeyStr);
                if (hotkey == null)
                {
                    logger.Error($"Cannot parse hotkey: {hotkeyStr}");
                    onComplete?.Invoke(RegResult.ParseError);
                    return false;

View on GitHub (pinned to 891d971682)

Solutions

  1. Check HotkeyCallbacks for the exact registered name and make the string passed to RegHotkeyFromString match it exactly (case-sensitive).
  2. If you removed the callback intentionally, also remove the RegHotkeyFromString call that references it.
  3. If you added a new hotkey, register its handler with HotkeyCallbacks.Add("YourCallbackName", handler) before RegHotkeyFromString runs.

Example fix

// before
RegHotkeyFromString(cfg.MoveUpKey, "MoveUpCallback"); // throws if not registered

// after
if (HotkeyCallbacks.GetCallback("MoveUpCallback") != null)
    RegHotkeyFromString(cfg.MoveUpKey, "MoveUpCallback");
Defensive patterns

Strategy: validation

Validate before calling

// Before calling RegHotkeyFromString, confirm the callback exists
if (HotkeyCallbacks.GetCallback(callbackName) == null)
{
    // skip or log instead of letting it throw
    return false;
}

Type guard

// Narrow to known callback names
static readonly HashSet<string> KnownCallbacks =
    new HashSet<string> { "ShowLogsCallback", "ServerMoveUpCallback", "ServerMoveDownCallback" };

bool IsValidCallbackName(string name) => KnownCallbacks.Contains(name);

Try / catch

try { RegHotkeyFromString(hotkeyStr, callbackName); }
catch (Exception ex) when (ex.Message.EndsWith("not found"))
{ /* log unknown callback name, do not abort all hotkey registration */ }

Prevention

When it happens

Trigger: Calling RegHotkeyFromString with a callbackName string that was never registered via HotkeyCallbacks.Add(...). This also happens if the registration key string is misspelled, has different casing, or if the registration code path that adds the callback never ran (e.g. the view/controller that owns the callback was never instantiated).

Common situations: Refactoring a callback and renaming it in one place but not the string literal passed to RegHotkeyFromString; removing a feature (logs/move-up/move-down) but leaving the RegHotkeyFromString("", "ShowLogsCallback") call behind; copy-pasting a new hotkey config line and forgetting to register the matching callback.

Related errors


AI-assisted analysis of shadowsocks/shadowsocks-windows@891d971682 (2026-08-13). Data as JSON: /api/errors/e2a156210026ce74. Report an issue: GitHub.