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

# Stop a runaway import

> You queued fifty thousand rows from the wrong table. Here is the kill switch, and the cleanup.

[← All use cases](https://docs.memory.anonalabs.com/use-cases/overview.md)

[API reference](https://docs.memory.anonalabs.com/api-reference/memories.md)

## The scenario

The backfill is running. Twenty seconds in you realise it is pointed at the
staging table, or the date filter was wrong, or it is one job per row instead of
one job per batch.

Every queued chunk is an LLM call you are paying for, and it will keep going
until it finishes.

**What this recipe shows that no other does:** operational control of work
already in flight — cancelling it, and tearing down the plumbing around it.

## Step 1 — Cancel the job

```python theme={null}
from anona import AnonaError

for job_id in job_ids:  # one per record_batch call — see below
    try:
        result = client.cancel_job(space_id="import", job_id=job_id)
        print(job_id, result["cancelled_parts"], "cancelled,", result["running_parts"], "already running")
    except AnonaError as e:
        if e.code != "job_not_cancellable":
            raise
        print(job_id, "nothing left to stop:", e.message)
```

The two numbers matter and they are not the same thing. **Cancelled parts stop.
Running parts finish** — work already handed to a worker is not interrupted, so
a large job keeps producing memories for a little while after you cancel it.
Watch, do not assume.

`409 job_not_cancellable` means there was nothing queued left to stop: every
part is already running or finished. A small batch is often a single part, so
once a worker has picked it up it runs to the end — the job then finishes
normally rather than reading `cancelled`, and the refusal is the truth.

A `record_batch` call takes **at most 100 items** (`422` above that), so a large
import is many jobs. Keep every `job_id` as you queue them; the loop above is
only as complete as that list.

## Step 2 — Find out what landed

```python theme={null}
page = client.list_memories(space_id="import", limit=100)
print(page["total"], "memories made it in")
```

## Step 3 — Undo the damage

If the import was file-based, deleting the document takes its memories with it:

```python theme={null}
client.delete_document(space_id="import", document_id=doc_id)
```

If it was a write of loose records and the space existed only for the import,
the honest cleanup is to
[delete the space](https://docs.memory.anonalabs.com/use-cases/one-space-or-many.md) and start again. Picking
individual bad memories out of a good space is slow and error-prone — which is
an argument for importing into a scratch space first.

## Step 4 — Turn off what was watching it

A cancelled import usually leaves a webhook that no longer has a job to report on.

```python theme={null}
for hook in client.list_webhooks(space_id="import"):
    print(hook["id"], hook["url"], hook["enabled"])

client.delete_webhook(space_id="import", webhook_id=hook_id)
```

Deleting stops queued deliveries for it — worth doing before your endpoint gets
a burst of events about a job you abandoned.

## Evals

Practise this before you need it, on a space you do not care about:

1. Queue several 100-item batches back to back, cancel them all after a few
   seconds.
2. Record `cancelled_parts` and `running_parts`, and which jobs answered
   `job_not_cancellable`.
3. Poll `list_memories` until `total` stops moving. The gap between cancelling
   and stopping is the number worth knowing — it is what you will be asked.
4. Confirm cleanup actually emptied it.

## Guardrails

> [!WARNING]
>
> **Cancelling does not refund what already ran.** Extraction that has happened
> is billed. The saving is on the part that had not started, which is why the
> first twenty seconds matter more than the next twenty minutes.

* **Import into a scratch space.** It converts "pick out the bad memories" into
  "delete the space", and that is the whole difference between a bad afternoon
  and a bad minute.
* **A cancelled job is a terminal state**, not a pause. There is no resume;
  re-import what you still want.
* **Throughput is bounded platform-side**, so a large import runs for a long
  time. That is exactly why the kill switch is worth knowing before you need it.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.