shadowsocks/shadowsocks-windows · error · ApplicationException

Plugin Program

Error message

Plugin Program

What it means

Thrown as ApplicationException wrapping a Win32Exception that occurred while starting the Sip003 plugin process, where the native error code is NOT 0x00000002 (file-not-found is handled separately). It is the catch-all for every other Process.Start failure: access denied, bad image, sharing violation, etc. The original Win32Exception is passed as the inner exception so the real native error is inspectable.

Source

Thrown at shadowsocks-csharp/Controller/Service/Sip003Plugin.cs:114

                _pluginProcess.StartInfo.Environment["SS_LOCAL_HOST"] = LocalEndPoint.Address.ToString();
                _pluginProcess.StartInfo.Environment["SS_LOCAL_PORT"] = LocalEndPoint.Port.ToString();
                _pluginProcess.StartInfo.Arguments = ExpandEnvironmentVariables(_pluginProcess.StartInfo.Arguments, _pluginProcess.StartInfo.EnvironmentVariables);
                try
                {
                    _pluginProcess.Start();
                }
                catch (System.ComponentModel.Win32Exception ex)
                {
                    // do not use File.Exists(...), it can not handle the scenarios when the plugin file is in system environment path.
                    // https://docs.microsoft.com/en-us/windows/win32/seccrypto/common-hresult-values
                    //if ((uint)ex.ErrorCode == 0x80004005)
                    //  https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d
                    if (ex.NativeErrorCode == 0x00000002)
                    {
                        throw new FileNotFoundException(I18N.GetString("Cannot find the plugin program file"), _pluginProcess.StartInfo.FileName, ex);
                    }
                    throw new ApplicationException(I18N.GetString("Plugin Program"), ex);
                }
                _pluginJob.AddProcess(_pluginProcess.Handle);
                _started = true;
            }

            return true;
        }

        public string ExpandEnvironmentVariables(string name, StringDictionary environmentVariables = null)
        {
            // Expand the environment variables from the new process itself
            if (environmentVariables != null)
            {
                foreach(string key in environmentVariables.Keys)
                {
                    name = name.Replace($"%{key}%", environmentVariables[key]);
                }
            }

View on GitHub (pinned to 891d971682)

Solutions

  1. Inspect ex.NativeErrorCode of the inner Win32Exception to get the exact Windows error and act on it (e.g. 5 = access denied, 193 = bad exe format).
  2. For access denied, run the client with sufficient privileges or fix file ACLs.
  3. For bad exe format, use a plugin built for the matching architecture.
  4. Add an antivirus exclusion or stop the conflicting process that locks the file.

Example fix

// before
throw new ApplicationException(I18N.GetString("Plugin Program"), ex);

// after: include the native error code for diagnosis
throw new ApplicationException(
    I18N.GetString("Plugin Program") + $" (NativeError 0x{ex.NativeErrorCode:X8})", ex);
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight: can the account read/execute the plugin?
var fi = new FileInfo(resolvedPluginPath);
if (!fi.Exists) /* handle before start */

Type guard

static string ClassifyWin32(int code) => code switch
{
    2 => "file-not-found",
    5 => "access-denied",
    193 => "bad-exe-format",
    _ => "other"
};

Try / catch

try { plugin.Start(); }
catch (ApplicationException ex) when (ex.InnerException is Win32Exception w)
{ /* branch on w.NativeErrorCode: 5 perms, 193 arch, etc. */ }

Prevention

When it happens

Trigger: ERROR_ACCESS_DENIED (the user/account cannot execute the file or the file is locked); ERROR_BAD_EXE_FORMAT / 0xC1 (the plugin is not a valid executable for this architecture, e.g. 64-bit plugin on a 32-bit host); ERROR_SHARING_VIOLATION (the file is open exclusively elsewhere); the plugin requires elevation and UAC blocks the launch.

Common situations: Running the client as a normal user but the plugin requires admin; an architecture mismatch (x64 plugin vs x86 client); antivirus blocking execution; the plugin file being written/replaced while it is being started.

Related errors


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