shadowsocks/shadowsocks-windows · error · Exception
Unable to set information. Error: {0}
Error message
Unable to set information. Error: {0} What it means
Exception thrown in the Job constructor when the Win32 SetInformationJobObject call fails. The job object is configured with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE (0x2000) so child processes die with the parent. The message embeds Marshal.GetLastWin32Error() — the system error code explaining why the limit could not be set.
Source
Thrown at shadowsocks-csharp/Util/ProcessManagement/Job.cs:41
var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION
{
LimitFlags = 0x2000
};
var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
BasicLimitInformation = info
};
try
{
int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
extendedInfoPtr = Marshal.AllocHGlobal(length);
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr,
(uint) length))
throw new Exception(string.Format("Unable to set information. Error: {0}",
Marshal.GetLastWin32Error()));
}
finally
{
if (extendedInfoPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(extendedInfoPtr);
extendedInfoPtr = IntPtr.Zero;
}
}
}
public bool AddProcess(IntPtr processHandle)
{
var succ = AssignProcessToJobObject(handle, processHandle);
if (!succ)
{
View on GitHub (pinned to 891d971682)
Solutions
- Read the numeric Win32 error in the message and look it up (5 = ERROR_ACCESS_DENIED, 6 = ERROR_INVALID_HANDLE, 87 = ERROR_INVALID_PARAMETER, 1001 = ERROR_NOT_SUPPORTED).
- Verify the process is running on a real Windows kernel with permission to create jobs.
- Confirm the marshalled struct size matches the OS bitness; the UIntPtr/UInt64 fields differ between x86 and x64.
- Check that CreateJobObject did not return IntPtr.Zero before calling SetInformationJobObject.
Example fix
// before
handle = CreateJobObject(IntPtr.Zero, null);
// ... SetInformationJobObject(handle, ...) throws if handle is zero
// after
handle = CreateJobObject(IntPtr.Zero, null);
if (handle == IntPtr.Zero)
throw new Exception("CreateJobObject failed: " + Marshal.GetLastWin32Error());
// ... then SetInformationJobObject Defensive patterns
Strategy: try-catch
Validate before calling
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
throw new PlatformNotSupportedException("Job objects require Windows");
// verify the job handle before SetInformationJobObject is reached
if (handle == IntPtr.Zero)
throw new Exception("CreateJobObject failed: " + Marshal.GetLastWin32Error()); Try / catch
try { var job = new Job(); job.AddProcess(proc.Handle); }
catch (Exception ex) {
// log the Win32 error code; children will not be auto-killed on exit
logger.Warn(ex, "job object unavailable; children may outlive the parent");
} Prevention
- Check the OS platform before constructing Job.
- Decode the Win32 error embedded in the message to find the root cause.
- Verify the marshalled struct sizes match the process bitness.
When it happens
Trigger: CreateJobObject returned IntPtr.Zero so SetInformationJobObject operates on a null handle. The process runs on a platform whose kernel32 stubs job-object calls. Insufficient privileges or a security policy denies job creation. The marshalled JOBOBJECT_EXTENDED_LIMIT_INFORMATION size does not match the OS bitness (UIntPtr fields change size), so the length check fails.
Common situations: Running on Wine or a non-Windows platform where the call is stubbed. An x86/x64 struct layout mismatch causing ERROR_INVALID_PARAMETER (87). A group policy or sandbox that blocks job creation.
Related errors
AI-assisted analysis of shadowsocks/shadowsocks-windows@891d971682 (2026-08-13).
Data as JSON: /api/errors/084972c2463d3345.
Report an issue: GitHub.