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

  1. Check the log traceback for 'Error cancelling export'.
  2. Verify via GET /export/status whether an export is actually active before cancelling.
  3. 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

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


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/74126a2efe311046. Report an issue: GitHub.