dotnet/wpf · error · PrintJobException

PrintSystemException.PrintSystemJobInfo.Deleted

Error message

PrintSystemException.PrintSystemJobInfo.Deleted

What it means

PrintSystemJobInfo.Pause was called on a job that is already in the Deleted state (JobStatus & Deleted != 0). Instead of attempting a spooler call, the method throws PrintSystemException with key 'PrintSystemException.PrintSystemJobInfo.Deleted'. You cannot pause a job that no longer exists in the print queue.

Solutions

  1. Check (job.JobStatus & PrintJobStatus.Deleted) != 0 before calling Pause
  2. Discard stale PrintSystemJobInfo references and re-fetch job state from the PrintQueue
  3. Treat this as an expected outcome in cleanup/monitoring code — catch and skip
  4. Use PrintQueue.GetPrintJobInfoFilter or refresh queue jobs rather than operating on cached objects

Example fix

// before
job.Pause(); // stale reference: job already deleted
// after
if ((job.JobStatus & PrintJobStatus.Deleted) == 0)
{
    job.Pause();
}
else
{
    job = queue.GetJob(job.JobIdentifier); // refresh from spooler
}
Defensive patterns

Strategy: validation

Validate before calling

if ((job.JobStatus & PrintJobStatus.Deleted) != 0)
{
    // job gone: re-fetch or skip
    job = job.HostingPrintQueue.GetJob(job.JobIdentifier);
    if (job == null) return; // genuinely gone
}
job.Pause();

Type guard

bool IsAlive(PrintSystemJobInfo job) => job != null && (job.JobStatus & PrintJobStatus.Deleted) == 0;

Try / catch

try { job.Pause(); }
catch (PrintSystemException ex) when (ex.Message.Contains("PrintSystemJobInfo.Deleted")) { /* benign: job already gone, refresh or skip */ }

Prevention

When it happens

Trigger: Calling Pause() on a PrintSystemJobInfo object cached from earlier while the job has since been deleted — e.g. it finished printing, was cancelled via Cancel(), or the user removed it from the print queue UI.

Common situations: Holding stale PrintSystemJobInfo references in a long-running app while jobs complete in the background; multiple components acting on the same job; monitoring code reacting to old queue snapshots.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/b44f81245aea92cc. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/System.Printing/CPP/src/PrintSystemJobInfo.cpp:421

    if (!isDeleted)
    {
        try
        {
            hostingPrintQueue->PrinterThunkHandler->ThunkSetJob(jobIdentifier, JOB_CONTROL_PAUSE);

            get_InternalPropertiesCollection("Status")->GetProperty("Status")->IsInternallyInitialized = true;
            this->JobStatusSecondary = static_cast<Int32>(jobStatus | PrintJobStatus::Paused);
        }
        catch (InternalPrintSystemException^ internalException)
        {
            throw CreatePrintJobException(internalException->HResult,
                                          "PrintSystemException.PrintSystemJobInfo.Generic");
        }
    }
    else
    {
       throw CreatePrintJobException("PrintSystemException.PrintSystemJobInfo.Deleted");
    }
}


void
PrintSystemJobInfo::
Resume(
    void
    )
{
    VerifyAccess();

    if (!isDeleted)
    {
        try
        {
            hostingPrintQueue->PrinterThunkHandler->ThunkSetJob(jobIdentifier, JOB_CONTROL_RESUME);

View on GitHub (pinned to 81131a70a4)