Migrating a dataset schema
A dataset’s schema rarely stays fixed for the life of a project. You add a field for a new annotation, relabel a column, or tighten validation. Changing the schema of a V4 dataset that already holds data starts a schema migration: an asynchronous job that re-normalises every existing datapoint against the new schema version, so old and new data stay consistent.
This guide covers what triggers a migration, how to track it, and how to handle the outcomes.
When a migration runs
You update a schema by patching the dataset:
Every successful PATCH writes a new schema version. Whether that triggers a migration depends on whether the dataset already had a schema:
Setting the first schema also releases any uploads that were parked waiting for one — imports left in pending_schema are re-enqueued and processed against the new schema.
Requirements
The PATCH is rejected before any version is written if:
The task_group_id designation is frozen because existing datapoints are keyed at ingestion and a migration never re-keys them — changing the grouping column would silently split grouping between old and new data. Other field changes (adding, removing, relabelling, retyping) are fine.
Tracking the migration
When a migration starts, capture the migration_job_id from the PATCH response:
Then poll the migration job until it reaches a terminal status:
Migration status
A complete job:
Handling a partial migration
A migration is partial when the datapoints are reprocessed but some field values are invalid under the new schema — for example, a column newly typed as a number that holds non-numeric text. The migration does not fail the whole job or block the change: it nulls the offending field on that datapoint, records it, and carries on.
reprocessed_count counts cleanly-migrated datapoints; failed_count counts datapoints that had at least one nulled field. To recover a nulled field, fix the source value and re-upload or append the corrected datapoint.
A failed job means the migration could not proceed — for instance the target schema version could not be resolved — and carries a reason. Nothing was reprocessed; the dataset’s datapoints remain on the previous version.
Concurrency with imports, appends, and syncs
A migration re-normalises the whole dataset in place, so it does not run alongside other writes to the same dataset:
- While a migration is
processing, an append (POST .../datapoints) is rejected with409— retry once the migration completes. - A file import in progress and a schema migration are likewise mutually exclusive on a dataset.
- A batch sync that overlaps a dataset write can end
failedwith a reason telling you to retry.
The migration itself is idempotent: it only reprocesses datapoints below the target version and retains each datapoint’s id, so a retried or redelivered run resumes from where it left off rather than double-writing.
Recipe: change a schema and track the migration
Patch the dataset with the new schema: PATCH /datasets/{dataset_id} with { "schema": { ... } }. Read migration_job_id from the response — if it’s absent, this was the dataset’s first schema and there’s nothing to migrate.
By using AI Task Builder, you agree to our AI Task Builder Terms.