Stirling-Tools/Stirling-PDF · error · Error

policy produced no output

Error message

policy produced no output

What it means

Thrown by runToCompletion in policyExport when a policy run reaches COMPLETED status but view.outputs[0] is missing — i.e. the pipeline finished successfully yet produced no downloadable file. The export path needs at least one output file to build the enforced PDF, so a completion with zero outputs is treated as a hard failure (the policy didn't do its job) rather than silently exporting the original.

Source

Thrown at frontend/editor/src/proprietary/services/policyExport.ts:101

/** Run one policy on a file and resolve the enforced bytes + run info (throws on
 *  failure). */
async function runToCompletion(
  backendId: string,
  file: File,
): Promise<PolicyRunResult> {
  const target = resolvePolicyRunTarget();
  const runId = await runStoredPolicy(backendId, [file]);
  for (let i = 0; i < MAX_POLLS; i++) {
    await delay(POLL_MS);
    let view;
    try {
      view = await getPolicyRun(runId);
    } catch {
      continue; // transient — keep polling within the cap.
    }
    if (view.status === "COMPLETED") {
      const out = view.outputs?.[0];
      if (!out) throw new Error("policy produced no output");
      const blob = await downloadPolicyOutput(out.fileId, target);
      // Keep the export's filename; only the bytes are the enforced result.
      const enforced = new File([blob], file.name, {
        type: blob.type || file.type || "application/pdf",
      });
      return { file: enforced, runId, target, outputs: view.outputs ?? [] };
    }
    if (view.status === "FAILED" || view.status === "CANCELLED") {
      throw new Error(view.error || `policy run ${view.status.toLowerCase()}`);
    }
    if (view.status === "WAITING_FOR_INPUT") {
      throw new Error(
        "policy requires interactive input and cannot run automatically",
      );
    }
  }
  throw new Error("policy run timed out");
}

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Inspect the policy automation to confirm it ends in a file-producing operation (e.g. save/convert) before the policy is set to runOn=export.
  2. Check the backend policy-run detail for outputs — confirm whether they were ever written or pruned.
  3. Increase output retention if artifacts are being GC'd before the poll completes.
  4. Surface the error to the user (the export wrapper falls back to the original file + warning toast) and log the runId for diagnosis.

Example fix

// before
if (!out) throw new Error("policy produced no output");

// after — keep the throw, but the caller already falls back to the original file
if (!out) {
  logPolicyRunAnomaly(runId, 'completed-without-output');
  throw new Error("policy produced no output");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before setting runOn=export, confirm the automation ends in a file-producing operation
const endsWithOutput = automation.operations.some((op) => producesFile(op));
if (!endsWithOutput) warn('This policy produces no file; it cannot enforce on export.');

Type guard

export function policyProducesFile(automation: { operations: Operation[] }): boolean {
  return automation.operations.some((op) => op.type === 'save' || op.type === 'convert');
}

Try / catch

// the export wrapper already falls back to the original file on this error:
try {
  enforced = await runToCompletion(backendId, file);
} catch (e) {
  if (/no output|timed out|FAILED|CANCELLED|interactive input/i.test(e instanceof Error ? e.message : "")) {
    warnExportWithOriginal(file, e);
    enforced = { file, runId: undefined, target, outputs: [] };
  } else throw e;
}

Prevention

When it happens

Trigger: The stored policy's automation has no file-producing operation; the backend marked the run COMPLETED but the output artifact was deleted/pruned before poll; an automation that only mutates metadata (no output file) was set as an export policy; a bug where the backend writes outputs to a different array index.

Common situations: User configures a policy whose operations don't emit a file (e.g. a metadata-only step) and sets runOn=export; backend output retention misconfigured so outputs are GC'd; a policy template was authored without a terminal output step.

Related errors


AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13). Data as JSON: /api/errors/1f9835a91a43f7a7. Report an issue: GitHub.