dotnet/wpf · error · PrintJobException
PrintSystemException.PrintSystemJobInfo.Generic
Error message
PrintSystemException.PrintSystemJobInfo.Generic
What it means
A generic print-job exception raised when PrintQueueStream.AbortOrCancel encounters an InternalPrintSystemException while attempting to abort or cancel the underlying spooler job. The original HRESULT is preserved in a PrintSystemException with message key PrintSystemException.PrintSystemJobInfo.Generic, so the real Win32/spooler error code must be read from the exception's HResult.
Solutions
- Read the HResult on the caught PrintSystemException to identify the underlying Win32 print error
- Guard against double-abort: only call Abort/Cancel once per stream and only while the job is still active
- Verify the Print Spooler service is running (services.msc) when aborts fail spuriously
- Catch PrintSystemException around Abort/Cancel and treat 'job not found' style HRESULTs as already-aborted
Example fix
// before
stream.Abort();
// after
try { stream.Abort(); }
catch (PrintSystemException ex) when (ex.InnerException is Win32Exception w && w.NativeErrorCode == 87) { /* job gone; ignore */ } Defensive patterns
Strategy: try-catch
Validate before calling
if (stream == null) throw new ArgumentNullException(nameof(stream));
if (stream.JobIdentifier <= 0) throw new InvalidOperationException("Stream has no active job"); Type guard
static bool CanAbort(PrintQueueStream s) => s != null && s.JobIdentifier > 0;
Try / catch
try { stream.Abort(); }
catch (PrintSystemException ex) { Log(ex.HResult); /* job likely already gone */ } Prevention
- Only Abort jobs that are still active (check JobStatus)
- Never call Abort/Cancel more than once per stream
- Verify the Print Spooler service is running before job manipulation
- Map the preserved HResult to the Win32 error to diagnose the abort failure
When it happens
Trigger: Calling PrintQueueStream.Abort or Cancel (which route to AbortOrCancel) when the internal thunk calls into the print spooler fail - e.g. the job handle is invalid, the job already completed or was deleted, or the spooler returns an error.
Common situations: Aborting a stream after the job already finished printing; double-Abort on the same stream; spooler service (Spooler SVC) stopped or restarted mid-operation; job deleted by another process.
Related errors
- PrintSystemException.PrintServer.Generic
- PrintSystemException.PrintServer.GetDefaultPrinter
- PrintSystemException.PrintServer.Refresh
- PrintSystemException.PrintSystemJobInfo.Create
- PrintSystemException.PrintSystemJobInfo.Generic
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/2c185c0aefbb4db1.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/System.Printing/CPP/src/PremiumPrintStream.cpp:415
// last commit operation and get reset to 0 as the data is commited.
// If interleaving is not enabled we write the data when the stream is closed,
// in which case bytesToCommit should be the total length of the stream.
//
CommitDataToPrinter();
printerThunkHandler->ThunkEndDocPrinter();
delete printerThunkHandler;
printerThunkHandler = nullptr;
jobIdentifier = 0;
bytesToCommit = 0;
bytesPreviouslyCommited = 0;
printerThunkHandler = nullptr;
}
}
catch (InternalPrintSystemException^ internalException)
{
throw PrintSystemJobInfo::CreatePrintJobException(internalException->HResult,
"PrintSystemException.PrintSystemJobInfo.Generic");
}
}
}
__finally
{
this->streamClosed = true;
System::Threading::Monitor::Exit(accessVerifier);
}
}
}
Int32
PrintQueueStream::JobIdentifier::
get(
void
)
{View on GitHub (pinned to 81131a70a4)