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
- 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.
- Check the backend policy-run detail for outputs — confirm whether they were ever written or pruned.
- Increase output retention if artifacts are being GC'd before the poll completes.
- 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
- Validate that a policy automation ends in a file-producing operation before allowing runOn=export.
- Monitor policy runs for 'completed-without-output' anomalies via the runId.
- Keep output retention long enough to outlast the poll window (≈2.5 min).
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
- view.error || policy run ${view.status.toLowerCase()}
- Unknown policy category: ${id}
- No pricing data returned
- No billing portal URL returned
- Supabase is not configured
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/1f9835a91a43f7a7.
Report an issue: GitHub.