# GDScript: Handles

Source: https://tweens.gd/gdscript/api/handles/

`Tweens.play()` returns a `TweensGdHandle` that controls that playback alone. It never returns `null`: a [rejected start](https://tweens.gd/gdscript/api/start/#rejected-starts) returns a handle that has already failed. [Await Completion](https://tweens.gd/gdscript/playback/) introduces handles.

## Control

| Member | Type | Meaning |
| --- | --- | --- |
| [`pause()`](https://tweens.gd/gdscript/api/handles/#pause) | `void` | Hold playback, in addition to any [pause mode](https://tweens.gd/gdscript/api/start/#tweenspause) |
| [`resume()`](https://tweens.gd/gdscript/api/handles/#resume) | `void` | Release that hold |
| [`is_paused`](https://tweens.gd/gdscript/api/handles/#is-paused) | `bool` | True while held by `pause()`; assignable |
| [`cancel()`](https://tweens.gd/gdscript/api/handles/#cancel) | `void` | Stop now and keep the latest value; safe to call again |

## Status

| Member | Type | Meaning |
| --- | --- | --- |
| [`state`](https://tweens.gd/gdscript/api/handles/#state) | `Tweens.State` | Where the timeline is; a paused handle keeps its state |
| [`progress`](https://tweens.gd/gdscript/api/handles/#progress) | `float` | Position in the current leg, from 0 to 1, before easing. It runs backward during a ping-pong return, and isn’t the share of all cycles completed |
| [`is_terminal`](https://tweens.gd/gdscript/api/handles/#is-terminal) | `bool` | True once completed, cancelled, or faulted |
| [`is_settled`](https://tweens.gd/gdscript/api/handles/#is-settled) | `bool` | True once the ending callbacks and cleanup have run |
| [`completion_reason`](https://tweens.gd/gdscript/api/handles/#completion-reason) | `Tweens.Reason` | Why playback ended; `-1` until it has |
| [`error`](https://tweens.gd/gdscript/api/handles/#error) | `String` | What went wrong, if playback failed; empty otherwise |
| [`target`](https://tweens.gd/gdscript/api/handles/#target) | `Object` | The animated object; `null` for a rejected start |
| [`value`](https://tweens.gd/gdscript/api/handles/#value) | `Variant` | The value captured at start, then the latest value written |

## Awaiting

| Member | Type | Meaning |
| --- | --- | --- |
| [`end`](https://tweens.gd/gdscript/api/handles/#end) | `Variant` | Await it directly: the `ended` signal while running, the reason once ended |
| [`wait(cancellation)`](https://tweens.gd/gdscript/api/handles/#wait-cancellation) | `Tweens.Reason` | Await the reason; the optional `TweensGdCancellation` cancels only this wait |
| [`ended(reason)`](https://tweens.gd/gdscript/api/handles/#ended-reason) | signal | Emitted once when playback ends |

Prefer `await handle.end` to awaiting `ended`: awaiting the signal after it fired waits forever.

### TweensGdCancellation

| Member | Type | Meaning |
| --- | --- | --- |
| [`TweensGdCancellation.new()`](https://tweens.gd/gdscript/api/handles/#tweensgdcancellation-new) | `TweensGdCancellation` | A token to pass to `wait()` |
| [`token.cancel()`](https://tweens.gd/gdscript/api/handles/#token-cancel) | `void` | End the waits that use this token with `WAIT_CANCELLED`; playback continues |
| [`token.is_cancelled`](https://tweens.gd/gdscript/api/handles/#token-is-cancelled) | `bool` | True after `cancel()` |
| [`token.cancelled`](https://tweens.gd/gdscript/api/handles/#token-cancelled) | signal | Emitted by `cancel()` |

## Tweens.State

| Constant | Meaning |
| --- | --- |
| [`Tweens.State.DELAYED`](https://tweens.gd/gdscript/api/handles/#tweens-state-delayed) | Waiting out the delay |
| [`Tweens.State.PLAYING`](https://tweens.gd/gdscript/api/handles/#tweens-state-playing) | Moving through a leg |
| [`Tweens.State.INTERVAL`](https://tweens.gd/gdscript/api/handles/#tweens-state-interval) | Holding at an endpoint, between legs or cycles |
| [`Tweens.State.COMPLETED`](https://tweens.gd/gdscript/api/handles/#tweens-state-completed) | Reached its natural end |
| [`Tweens.State.CANCELLED`](https://tweens.gd/gdscript/api/handles/#tweens-state-cancelled) | Stopped early |
| [`Tweens.State.FAULTED`](https://tweens.gd/gdscript/api/handles/#tweens-state-faulted) | Stopped by a detected problem; see `error` |

## Tweens.Reason

| Constant | Meaning |
| --- | --- |
| [`Tweens.Reason.COMPLETED`](https://tweens.gd/gdscript/api/handles/#tweens-reason-completed) | Reached its natural end |
| [`Tweens.Reason.CANCELLED`](https://tweens.gd/gdscript/api/handles/#tweens-reason-cancelled) | `cancel()` or `cancel_tweens()` stopped it |
| [`Tweens.Reason.TARGET_FREED`](https://tweens.gd/gdscript/api/handles/#tweens-reason-target-freed) | The target was queued for deletion, or found freed |
| [`Tweens.Reason.OWNER_EXITED`](https://tweens.gd/gdscript/api/handles/#tweens-reason-owner-exited) | The owner left the scene tree, or a separate owner node was queued for deletion |
| [`Tweens.Reason.RUNNER_DISPOSED`](https://tweens.gd/gdscript/api/handles/#tweens-reason-runner-disposed) | The runner, its tree, or a manual scheduler shut down |
| [`Tweens.Reason.FAILED`](https://tweens.gd/gdscript/api/handles/#tweens-reason-failed) | The start was rejected, or playback detected a problem; see `error` |
| [`Tweens.Reason.WAIT_CANCELLED`](https://tweens.gd/gdscript/api/handles/#tweens-reason-wait-cancelled) | Only from `wait()`: its token was cancelled, and playback continues |

Compare against `COMPLETED` rather than a particular early reason: a node that owns its handle, as node targets do by default, reports `TARGET_FREED` after `queue_free()` but `OWNER_EXITED` after `free()`, because `free()` removes it from the tree before deleting it.

## Errors

-   GDScript has no exceptions to throw, so failures are data. A tween that detects a problem ends with `FAILED`, and `error` holds the message; several problems are joined with newlines.
-   `on_finally` still runs, other tweens keep playing, and the automatic runner reports the message to Godot’s error log.
-   A rejected start’s `pause()`, `resume()`, `cancel()`, and `wait()` stay safe to call.

Script errors aren’t caught

tweens.gd detects invalid configuration, stale Callables, non-numeric or non-finite easing, and non-finite interpolation. An error inside your own callback or property setter stays an ordinary Godot script error, and isn’t guaranteed to become `FAILED`.

## Threading

-   Create and control tweens, and await `end`, on Godot’s main thread.
-   A call from another thread reports an error and does nothing: starts return a handle that has already failed, and `wait()` returns `FAILED`.
-   Keep callbacks synchronous; put code that awaits after `await handle.end`.
