## TL;DR
The part is already attached, so the migration step is telling you its work is done, not that it failed. Query system.parts to confirm the part exists with the expected row count; if the data is correct, skip the attach and continue. If the data is wrong, detach or drop the bad part first, then attach the right one. Never force-attach over a part you have not inspected.

## The query

```text
clickhouse error: ATTACH PARTITION failed during table migration - part already exists
```

## Use this when

- clickhouse ATTACH PARTITION fails with "part already exists"
- A table migration re-runs an attach step
- Idempotency check for partition attach migrations
- An agent's clickhouse migration fails on the second run

## Not for

- ATTACH PARTITION failing because the source part is missing (check the source table)
- Detached-part or filesystem permission errors (a different failure)
- Replicated-table attach quirks across replicas (check replication queue)

## Steps

### 1. Inspect the existing part

```sql
SELECT partition_id, name, rows, active FROM system.parts
WHERE table = '[table]' AND database = '[db]' AND partition_id = '[partition]';
```

Expected output: the part row showing it is active with a row count. Compare the count against the source: matching counts mean the attach already succeeded.

### 2. Case A: the data is correct - skip the attach

If the part is active and the row count matches the source, the migration step already did its job (probably on a previous partial run). Mark the step done in whatever tracker the agent uses and continue with the next step.

Expected output: the migration proceeds without re-attaching. The error was idempotency feedback, not a failure.

### 3. Case B: the data is wrong - replace the part deliberately

```sql
ALTER TABLE [db].[table] DETACH PARTITION ID '[partition]';
```

Inspect the detached part, then attach the correct one:

```sql
ALTER TABLE [db].[table] ATTACH PARTITION ID '[partition]' FROM [db].[source_table];
```

Expected output: the bad part is detached (recoverable from the detached directory) and the correct part attaches cleanly.

### 4. Make the migration step idempotent

Guard future attach steps with a system.parts check: only attach when the part is absent or inactive. An agent re-running the migration then skips completed steps instead of erroring.

Expected output: the second run of the migration is a clean no-op on already-attached partitions.

## Tool compatibility

clickhouse 23.x and 24.x. ATTACH/DETACH PARTITION and system.parts are stable across these versions.

## Variant phrasings

### clickhouse ATTACH PARTITION part already exists

Steps 1 and 2: confirm the part is good, then skip. The error usually means success already happened.

### clickhouse attach partition idempotency

Step 4: guard the attach with a system.parts existence check so re-runs are safe.

### clickhouse replace bad attached part

Step 3: detach first, verify, then attach the correct part. Detach keeps the data recoverable.

## Why it happens

ClickHouse parts are immutable and identified by name; attaching a part that is already active would create two live copies of the same data, so the server refuses. The error is the database enforcing part identity, and in a migration context it almost always means a previous attempt already attached it.

## Edge cases

- An active part with the wrong row count is worse than a missing part: investigate the source before replacing, or you will attach bad data twice.
- On replicated tables, check the part on the right replica: "already exists" on one replica does not mean the cluster is consistent.
- Detached parts linger in the detached directory consuming disk: clean up after you are sure the replacement is good.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_BdisH2lTgRZ2zyTmrVYDZg
