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

  1. Read the HResult on the caught PrintSystemException to identify the underlying Win32 print error
  2. Guard against double-abort: only call Abort/Cancel once per stream and only while the job is still active
  3. Verify the Print Spooler service is running (services.msc) when aborts fail spuriously
  4. 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

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


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)