Stirling-Tools/Stirling-PDF · warning · Error
policy requires interactive input and cannot run automatical
Error message
policy requires interactive input and cannot run automatically
What it means
Thrown during export-time policy enforcement when the backend policy run returns a status of WAITING_FOR_INPUT. The export path polls the policy runner via getPolicyRun() inside runToCompletion(); an interactive policy cannot be auto-resolved because there is no UI surface mid-export to capture user input, so the run is treated as a hard terminal state. The module header states export is never hard-blocked — the caller catches this and falls back to the original file with a warning toast.
Source
Thrown at frontend/editor/src/proprietary/services/policyExport.ts:113
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");
}
function enforcedFilesSummary(names: string[]): string {
if (names.length === 1) return names[0];
if (names.length === 2)
return i18n.t("policies.enforcement.summaryTwo", {
first: names[0],
second: names[1],
});
return i18n.t("policies.enforcement.summaryMore", {
first: names[0],
second: names[1],
more: names.length - 2,View on GitHub (pinned to 9ef20dcab8)
Solutions
- Change the policy's runOn from 'export' to 'manual' so interactive steps never block the export path
- Configure the policy's backend to auto-resolve interactive decisions (auto-approve / auto-redact) so it reaches COMPLETED without WAITING_FOR_INPUT
- Split the policy: run the interactive portion on-demand before export, and only attach the deterministic portion to export enforcement
- Ensure the export caller catches this specific error and falls back to exporting the original file with a warning toast (the module is designed for this)
Example fix
// before
const result = await runToCompletion(backendId, file);
return result.file;
// after
try {
const result = await runToCompletion(backendId, file);
return result.file;
} catch (e) {
if (e instanceof Error && e.message.includes('interactive input')) {
alert(i18n.t('policies.enforcement.interactiveSkipped'), 'warning');
return file; // fall back to original
}
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Check if the policy has interactive steps before export
const policies = activeExportPolicies();
const hasInteractive = policies.some((p) => policyCatalogHasInteractiveSteps(p.categoryId));
if (hasInteractive) {
// Warn user that interactive policies will fall back to original file
showInteractivePolicyWarning();
} Try / catch
try {
const result = await runToCompletion(backendId, file);
enforcedFile = result.file;
} catch (e) {
if (e instanceof Error && e.message.includes('interactive input')) {
enforcedFile = file; // fall back to original per module contract
showToast('policies.enforcement.interactiveSkipped', 'warning');
} else {
throw e;
}
} Prevention
- Never set a policy with interactive steps to runOn:'export' — use 'manual' instead
- Review policy configurations in the catalog for interactive flags before enabling export enforcement
- Always catch runToCompletion errors in the export caller since the module contract guarantees fallback to the original file
When it happens
Trigger: A policy configured with runOn:'export' contains an interactive step (e.g. redaction approval, classification label selection, review checkpoint). The runStoredPolicy call succeeds and starts a run, but getPolicyRun polls return status 'WAITING_FOR_INPUT' before reaching COMPLETED.
Common situations: Policy authored with a human-review gate that is also flagged for automatic export enforcement; backend classification engine flags content it cannot auto-decide on; policy configuration drift where an interactive policy is accidentally set to runOn export.
Related errors
- policy run timed out
- policy produced no output
- view.error || policy run ${view.status.toLowerCase()}
- No pages to export
- Failed to export PDF: ${error instanceof Error ? error.messa
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/56cedc11a8eb5f0a.
Report an issue: GitHub.