# Why YuE2Pipeline.__call__ Raises InterruptedError on Cancellation Instead of Returning Partial Results

> Understand why YuE2Pipeline raises InterruptedError on cancellation instead of returning partial results. Learn about atomic contracts and efficient computation handling.

- Repository: [multimodal-art-projection/YuE](https://github.com/multimodal-art-projection/YuE)
- Tags: internals
- Published: 2026-09-14

---

**YuE2Pipeline raises `InterruptedError` to maintain atomic result contracts, abort expensive computations before VAE decoding, and provide unambiguous cancellation signals to the progress tracking system.**

The YuE music generation framework implements cooperative cancellation through a callable `cancelled` flag, yet deliberately raises an exception rather than returning partial data. This architectural decision ensures that `SongResult` objects always contain valid waveform audio while preventing wasted GPU cycles on abandoned generation requests.

## The Four-Stage Pipeline and Cancellation Checkpoint

`YuE2Pipeline.__call__` orchestrates a sequential inference pipeline consisting of four distinct stages:

1. **Plan** – Create a symbolic plan for the ABC score representation
2. **Semantic generation** – Generate discrete token sequences from the plan
3. **Neural audio rendering (NAR)** – Synthesize latent audio frame representations
4. **VAE decoding** – Convert latent frames into final waveform audio

Cancellation is supported by passing a callable `cancelled` parameter to the pipeline. The system evaluates this flag at a strategic boundary: **after** NAR completes but **before** the costly VAE decoding step begins.

### Where the Cancellation Check Occurs

In [`main/src/yue2/pipeline.py`](https://github.com/multimodal-art-projection/YuE/blob/main/main/src/yue2/pipeline.py) at lines 89–91, the pipeline explicitly checks the cancellation state:

```python
if cancelled():
    raise InterruptedError("Cancelled before VAE")

```

This checkpoint ensures that aborted requests never trigger the VAE decoder, which represents the most computationally expensive phase of the generation process.

## Design Rationale for Exception-Based Cancellation

The decision to raise `InterruptedError` rather than return partial latent tensors stems from four core architectural requirements.

### Enforcing Atomic Result Contracts

A `SongResult` object guarantees the presence of complete, decoded audio waveform data. At the NAR checkpoint, the pipeline holds only latent representations—unusable by downstream audio processing code. Returning a partially populated result would violate the API contract and potentially cause runtime errors in consumer applications expecting valid PCM data.

### Preventing Expensive VAE Decoding

VAE decoding consumes significant GPU/CPU resources to transform latent frames into audio waveforms. When `cancelled()` returns `True`, the pipeline aborts immediately to avoid wasting compute cycles on results that will be discarded. This early-exit strategy preserves hardware resources for concurrent or subsequent generation requests.

### Consistent Progress Reporting

The `Progress` helper class in [`main/src/yue2/progress.py`](https://github.com/multimodal-art-projection/YuE/blob/main/main/src/yue2/progress.py) (lines 61–68) maps `InterruptedError` and `KeyboardInterrupt` to a specific *cancelled* exit status. The `_exit_status` logic treats these exceptions as intentional termination events rather than failures:

```python

# Simplified from progress.py _exit_status logic

if isinstance(exc, (InterruptedError, KeyboardInterrupt)):
    status = "cancelled"
else:
    status = "error"

```

This mapping allows the progress UI to render a definitive "Cancelled" completion line rather than an ambiguous partial summary or error trace.

### Explicit Error Propagation Semantics

Raising an exception forces calling code to handle cancellation explicitly through `try/except` blocks. This pattern provides developers with clear hooks for resource cleanup, retry logic, or telemetry logging. Silent returns of partial data could be overlooked by client implementations, leading to subtle bugs where latent tensors propagate into audio processing pipelines expecting decoded waveforms.

## Key Source Files and Responsibilities

| File | Role |
|------|------|
| [`main/src/yue2/pipeline.py`](https://github.com/multimodal-art-projection/YuE/blob/main/main/src/yue2/pipeline.py) | Core orchestration; contains the cancellation checkpoint at lines 89–91 |
| [`main/src/yue2/progress.py`](https://github.com/multimodal-art-projection/YuE/blob/main/main/src/yue2/progress.py) | Progress UI implementation; maps `InterruptedError` to cancelled status at lines 61–68 |
| [`main/src/yue2/protocol.py`](https://github.com/multimodal-art-projection/YuE/blob/main/main/src/yue2/protocol.py) | Defines `SongResult` and generation configuration data structures |
| [`main/src/yue2/sampling.py`](https://github.com/multimodal-art-projection/YuE/blob/main/main/src/yue2/sampling.py) | Token generation implementation; respects `cancelled` callback during streaming |
| [`main/src/yue2/nar.py`](https://github.com/multimodal-art-projection/YuE/blob/main/main/src/yue2/nar.py) | Neural audio rendering; receives `cancelled` callback for early termination |

## Handling Cancellation in Practice

The following pattern demonstrates safe cancellation handling using a time-based trigger:

```python
import time
from yue2 import YuE2Pipeline

def cancel_after_seconds(limit):
    start = time.time()
    return lambda: (time.time() - start) > limit

pipeline = YuE2Pipeline.from_pretrained("multimodal-art-projection/YuE")

try:
    result = pipeline(
        style="pop",
        lyrics="Hello world",
        cancelled=cancel_after_seconds(2),
    )
except InterruptedError as e:
    print("Generation was cancelled:", e)
    # Perform cleanup or logging here

else:
    # Normal path: result.audio contains valid waveform data

    audio = result.audio
    # Process complete audio...

```

If the cancellation trigger fires before VAE decoding begins, the pipeline raises `InterruptedError` immediately, allowing the caller to handle the abort condition without receiving incomplete data.

## Summary

- **Atomicity guarantee**: `InterruptedError` prevents latent tensors from masquerading as final audio in `SongResult` objects.
- **Resource efficiency**: Cancellation aborts generation before expensive VAE decoding consumes GPU resources.
- **Progress clarity**: The `Progress` class explicitly maps `InterruptedError` to a "cancelled" status for clean UI termination.
- **Explicit control**: Exception-based cancellation requires client code to acknowledge and handle the abort condition.

## Frequently Asked Questions

### What happens if cancellation occurs during the NAR stage?

The NAR (Neural Audio Rendering) module accepts the same `cancelled` callback parameter and checks it during latent frame generation. If cancellation triggers during NAR, the pipeline halts before reaching the VAE checkpoint, still raising `InterruptedError` when control returns to `YuE2Pipeline.__call__`.

### Can I retrieve the latent representations if generation is cancelled?

No. The pipeline does not expose intermediate latent tensors when raising `InterruptedError`. The design intentionally discards these partial representations to maintain the invariant that all `SongResult` objects contain valid decoded audio. Users requiring intermediate access would need to modify [`pipeline.py`](https://github.com/multimodal-art-projection/YuE/blob/main/pipeline.py) to capture latents before the cancellation check at lines 89–91.

### How does the Progress tracker distinguish between errors and cancellations?

According to [`main/src/yue2/progress.py`](https://github.com/multimodal-art-projection/YuE/blob/main/main/src/yue2/progress.py) lines 61–68, the `_exit_status` method checks exception types: `InterruptedError` and `KeyboardInterrupt` map to the "cancelled" status, while all other exceptions map to "error". This distinction allows the UI to render appropriate termination messages and exit codes.

### Is the VAE decoding step significantly more expensive than NAR?

Yes. VAE decoding transforms high-dimensional latent frames into raw audio waveforms through computationally intensive tensor operations. The cancellation checkpoint specifically targets this boundary because NAR produces compact latent representations quickly, while VAE decoding scales linearly with audio duration and consumes the majority of inference time for long sequences.