unslothai/unsloth · error · HTTPException
Failed to cancel export
Error message
Failed to cancel export
What it means
Catch-all HTTP 500 when cancel_export raises. Note the design: backend.cancel_export returns a boolean (True if an export was actually killed, False if none was active), and False is a SUCCESS response ('No active export to cancel'); this 500 only fires on a genuine exception during termination.
Source
Thrown at studio/backend/routes/export.py:166
@router.post("/cancel", response_model = ExportOperationResponse)
async def cancel_export(current_subject: str = Depends(get_current_subject)):
"""Cancel the in-flight export by terminating its worker subprocess.
Only the export subprocess is killed; training and inference run in their
own subprocesses and keep going.
"""
try:
backend = get_export_backend()
cancelled = await asyncio.to_thread(backend.cancel_export)
return ExportOperationResponse(
success = True,
message = "Export cancelled" if cancelled else "No active export to cancel",
)
except Exception as e:
logger.error(f"Error cancelling export: {e}", exc_info = True)
raise HTTPException(
status_code = 500,
detail = "Failed to cancel export",
)
@router.get("/status", response_model = ExportStatusResponse)
async def get_export_status(current_subject: str = Depends(get_current_subject)):
"""Get export backend status (loaded checkpoint, model type, PEFT flag)."""
try:
backend = get_export_backend()
last_op = backend.get_last_op()
# Relativise the recovered output path the same way the per-op POST response
# does, so the success banner shows an identical path on either route.
last_op_output_path = None
if last_op and last_op.get("output_path"):
details = await asyncio.to_thread(_export_details, last_op["output_path"])
last_op_output_path = (details or {}).get("output_path")
return ExportStatusResponse(View on GitHub (pinned to 203007d190)
Solutions
- Check the log traceback for 'Error cancelling export'.
- Verify via GET /export/status whether an export is actually active before cancelling.
- If the subprocess is orphaned, kill it at the OS level (ps + kill) and restart the backend.
Defensive patterns
Strategy: try-catch
Validate before calling
const st = await api.get('/export/status');
if (!st.is_export_active) return; // nothing to cancel; avoids the call entirely Try / catch
try {
const r = await api.post('/export/cancel');
note(r.message); // 'Export cancelled' or 'No active export to cancel'
} catch (e) {
if (e.status === 500) checkServerLogs('Error cancelling export');
} Prevention
- Check is_export_active before cancelling — 'no active export' is a success, not an error.
- Handle orphaned subprocesses at the OS level, not by repeat cancels.
When it happens
Trigger: POST /export/cancel when the backend fails to terminate the export subprocess — e.g. the process handle is stale, the subprocess already became a zombie, or OS-level kill permission errors.
Common situations: Cancelling after the worker crashed or was killed externally; PID reuse racing the kill; sandboxed environments restricting process termination.
Related errors
- Failed to load checkpoint
- Memory cleanup failed. See server logs for details.
- Failed to cleanup export memory
- Failed to get export status
- Failed to get export logs
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/74126a2efe311046.
Report an issue: GitHub.