Stirling-Tools/Stirling-PDF · info · Error
Operation was cancelled
Error message
Operation was cancelled
What it means
Thrown in the per-file processing loop when `axios.isCancel(error)` is true — i.e. the request was aborted via the operation's cancelToken. This is not a backend failure; it is an intentional cancellation (user clicked Cancel, or the component holding the token unmounted). The original Cancel is preserved on `cause`.
Source
Thrown at frontend/editor/src/core/hooks/tools/shared/useToolApiCalls.ts:108
});
failedFiles.push(file.name);
try {
markFileError?.(file.fileId);
} catch (e) {
console.debug("markFileError", e);
}
continue;
}
processedFiles.push(...responseFiles);
// record source id as successful
successSourceIds.push(file.fileId);
console.debug("[processFiles] Success", {
name: file.name,
produced: responseFiles.length,
});
} catch (error) {
if (axios.isCancel(error)) {
throw new Error("Operation was cancelled", { cause: error });
}
console.error("[processFiles] Failed", { name: file.name, error });
failedFiles.push(file.name);
// mark errored file so UI can highlight
try {
markFileError?.(file.fileId);
} catch (e) {
console.debug("markFileError", e);
}
}
}
if (failedFiles.length > 0 && processedFiles.length === 0) {
throw new Error(
`Failed to process all files: ${failedFiles.join(", ")}`,
);
}
View on GitHub (pinned to 9ef20dcab8)
Solutions
- Treat cancellation as expected control flow: catch it and stop without surfacing an error toast.
- Ensure cancelOperation is wired to UI cancel affordances and called on component unmount via useEffect cleanup.
- If cancellation fires unexpectedly, audit for accidental double-invocation of cancelToken.cancel (e.g. a stale ref).
- Do not retry cancelled operations automatically — cancellation is user intent.
Example fix
// before
if (axios.isCancel(error)) {
throw new Error("Operation was cancelled", { cause: error });
}
// after — propagate a distinct, non-error signal the UI can treat as expected
if (axios.isCancel(error)) {
const cancelErr = new Error("Operation was cancelled", { cause: error });
cancelErr.name = "CancelledError";
throw cancelErr;
}
// caller:
} catch (e) {
if (e instanceof Error && e.name === "CancelledError") { onStatus("Cancelled"); return; }
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Do not invoke if the operation is already cancelled
if (cancelTokenRef.current?.token.reason) {
// skip the call; the user already cancelled
} Type guard
function isCancelledError(e: unknown): boolean {
return e instanceof Error && e.message === "Operation was cancelled";
} Try / catch
} catch (e) {
if (e instanceof Error && (e.message === "Operation was cancelled" || axios.isCancel((e as { cause?: unknown }).cause))) {
// expected control flow — stop without an error toast
onStatus("Cancelled");
return;
}
throw e;
} Prevention
- Treat cancellation as expected flow; never surface it as an error toast.
- Wire cancelOperation to UI affordances and component-unmount cleanup.
- Do not auto-retry cancelled operations — cancellation is user intent.
When it happens
Trigger: User clicks the Cancel button on a long-running operation (cancelOperation cancels cancelTokenRef.current.token); the component unmounts mid-operation and the parent cancels; an automation chain cancels a step.
Common situations: Cancelling a large multi-file compress/split; navigating away from the tool view while a batch is running; cancelling an automation step.
Related errors
- No team resolved yet
- Failed to process all files: ${failedFiles.join(", ")}
- ${operationName} operation failed: ${error.response?.data ||
- Failed to submit signature
- Failed to decline
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/160278ef5742a65b.
Report an issue: GitHub.