shadowsocks/shadowsocks-windows · error · FileNotFoundException
Cannot find the plugin program file
Error message
Cannot find the plugin program file
What it means
Thrown as FileNotFoundException when Process.Start fails with a Win32Exception whose NativeErrorCode is 0x00000002 (ERROR_FILE_NOT_FOUND). It means the Sip003 plugin executable named in StartInfo.FileName could not be located on disk or resolved through the system PATH. The inner Win32Exception is preserved, and the message reports the resolved filename.
Source
Thrown at shadowsocks-csharp/Controller/Service/Sip003Plugin.cs:112
var localPort = GetNextFreeTcpPort();
LocalEndPoint = new IPEndPoint(IPAddress.Loopback, localPort);
_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
- Set the plugin command to an absolute path to the executable.
- Add the plugin's directory to the system PATH (and restart the app so it inherits the new PATH).
- Verify the file exists at the resolved location and the app has execute/read permission on it.
- Check the StartInfo.FileName actually being passed (environment variables may not be expanded).
Example fix
// before _pluginProcess.StartInfo.FileName = "v2ray-plugin"; // not on PATH // after _pluginProcess.StartInfo.FileName = @"C:\Tools\v2ray-plugin\v2ray-plugin.exe";
Defensive patterns
Strategy: validation
Validate before calling
// Resolve the plugin path before starting
string resolved = ExpandEnvironmentVariables(plugin.Command);
if (!File.Exists(resolved) && !IsOnPath(resolved))
throw new FileNotFoundException("Plugin not found", resolved); Type guard
bool PluginPathLooksValid(string p) =>
!string.IsNullOrWhiteSpace(p) &&
(Path.IsPathRooted(p) || p.IndexOf(Path.DirectorySeparatorChar) >= 0 || IsOnPath(p)); Try / catch
try { plugin.Start(); }
catch (FileNotFoundException ex) when (ex.Message.Contains("plugin program file"))
{ /* tell user to set full path or install plugin on PATH */ } Prevention
- Store plugin commands as absolute paths in config.
- On startup, verify each configured plugin file is reachable from the app's account.
- Document that bare names require the plugin directory on the system PATH.
When it happens
Trigger: Plugin configured with a bare command name (e.g. "v2ray-plugin") that is neither in the working directory nor on PATH; a relative path that resolves against the wrong working directory; plugin file deleted/moved after config was written; PATH not inherited because the app was launched from a context with a restricted environment.
Common situations: User installs a plugin to a custom folder and only sets the filename without full path; portable distribution where the plugin is bundled but PATH is not set; running as a service under an account whose PATH differs from the interactive user; typo in the plugin command.
Related errors
AI-assisted analysis of shadowsocks/shadowsocks-windows@891d971682 (2026-08-13).
Data as JSON: /api/errors/a4cd9b9d3ce78067.
Report an issue: GitHub.