> ## Documentation Index
> Fetch the complete documentation index at: https://docs.youka.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Tasks

> Inspect tasks and wait for async operations to finish

Every async operation in Youka eventually runs as a task, but the primary SDK surface now returns operation handles instead of raw task IDs. Most callers should use `client.projects.wait(...)` or `client.exports.wait(...)` and only reach for `client.tasks.*` when they need low-level task inspection.

## `client.tasks.get(taskId, options?)`

Fetch the current state of a task by ID.

```ts theme={null}
const task = await client.tasks.get("tsk_abc123");
console.log(task.status, task.type);
```

### Task statuses

| Status        | Terminal? | Meaning                                    |
| ------------- | --------- | ------------------------------------------ |
| `created`     | No        | Task was created but not yet queued.       |
| `queued`      | No        | Task is waiting to run.                    |
| `in-progress` | No        | Task is currently executing.               |
| `completed`   | Yes       | Task finished successfully.                |
| `finalized`   | Yes       | Task finished and post-processing is done. |
| `failed`      | Yes       | Task failed with an error.                 |
| `cancelled`   | Yes       | Task was cancelled.                        |
| `timed-out`   | Yes       | Task hit its time limit.                   |

## `client.tasks.wait(taskId, options?)`

Poll a task until it reaches a terminal state. Returns the final task on success, throws `YoukaTaskError` on failure.

```ts theme={null}
const task = await client.tasks.wait("tsk_abc123", {
  pollIntervalMs: 3_000,
  signal: abortController.signal,
});
```

### Options

<ParamField path="pollIntervalMs" type="number">
  Milliseconds between polls. Defaults to `2000`.
</ParamField>

<ParamField path="signal" type="AbortSignal">
  Abort the wait. The in-flight request and any pending delay are cancelled
  immediately.
</ParamField>

### Errors

`client.tasks.wait(...)` throws `YoukaTaskError` when the task ends in `failed`, `cancelled`, or `timed-out`:

```ts theme={null}
import { YoukaTaskError } from "@youka/sdk";

try {
  await client.tasks.wait("tsk_abc123");
} catch (error) {
  if (error instanceof YoukaTaskError) {
    console.error(error.code); // TASK_FAILED | TASK_CANCELLED | TASK_TIMED_OUT
    console.error(error.task); // Full RestTask payload
  }
  throw error;
}
```

## `client.projects.wait(operation, options?)`

Wait for a project-scoped operation to finish, then refetch the project. Returns the operation handle, the terminal task, and the updated project.

```ts theme={null}
const operation = await client.projects.create({
  source: { type: "path", path: "./song.mp3" },
});

const { project, task } = await client.projects.wait(operation, {
  pollIntervalMs: 2_500,
});

console.log("Project ready:", project.id);
console.log("Task finished in state:", task.status);
```

<ParamField path="operation" type="ProjectOperation" required>
  Usually the result of `client.projects.create(...)`,
  `client.projects.separateStems(...)`, or `client.projects.syncLyrics(...)`.
</ParamField>

## `client.exports.wait(operationOrId, options?)`

Wait for a cloud export to reach a terminal state. Pass either the `ExportOperation` returned by `client.exports.create(...)` or an `exportId` string.

```ts theme={null}
const operation = await client.exports.create("prj_abc123", {
  resolution: "1080p",
  quality: "high",
});

const finalized = await client.exports.wait(operation, {
  pollIntervalMs: 3_000,
});

console.log(finalized.status, finalized.url);
```

## Cancellation

Pass an `AbortSignal` to cancel a long-running wait:

```ts theme={null}
const controller = new AbortController();

setTimeout(() => controller.abort(), 60_000);

try {
  await client.projects.wait(operation, { signal: controller.signal });
} catch (error) {
  if (error instanceof Error && error.name === "AbortError") {
    console.log("Wait cancelled after 60s");
  } else {
    throw error;
  }
}
```

The same signal also cancels the underlying task or export polling request.

## What's next

* [Errors](/en/sdk/errors) — handle `YoukaTaskError` and retryable errors
* [Exports](/en/sdk/exports) — wait for an export to finish
* [API async jobs](/en/api/async-jobs) — the same pattern in raw HTTP
