<!-- # hard line break macro for HTML -->

# fiftyone.core.label_schema_docs

Named label-schema documents: storage, CRUD and tier resolution.

A label schema document is a self-contained, named schema for a
dataset. The Schema Manager authors documents and the App’s “schema
lens” reads them: viewing a dataset through a schema hides its hidden
fields and attributes from the sidebar and from the App’s queries. In
FiftyOne the lens is a visibility preference chosen in the client;
FiftyOne Enterprise additionally enforces a schema server-side for
annotation tasks, which reference a document by id. The
`@voxel51/label-schemas` plugin exposes the CRUD below as operators.

Each document is stored as two SEPARATE halves (kept separable on
purpose — `visibility` can later lift into shared, named policy docs
without a migration of `label_schema`):

```default
{
    "_id": str, "dataset_id": ObjectId, "name": str,
    "description": str, "created_by": str,
    "created_at": int, "updated_at": int, "version": int,

    # The annotation CONTENT: today's ``dataset.label_schema`` entry
    # shape, verbatim per field — byte-compatible with the dataset's
    # own stored schemas so copies/fallbacks are pure synthesis.
    "label_schema": {
        "<field_path>": {type, component, classes, attributes[],
                         read_only, bbox, label, ...},
    },

    # The VISIBILITY policy: structured, no dotted keys.
    "visibility": {
        "default": "explore" | "hidden",     # unlisted fields
        "fields": {
            "<field_path>": {
                "tier": "annotate" | "explore" | "hidden",
                # omitted attribute => "annotate"
                "attributes": {"<attr>": "annotate"|"explore"|"hidden"},
            },
        },
    },
}
```

Storage is the `label_schemas` collection ([`COLLECTION`](#fiftyone.core.label_schema_docs.COLLECTION)),
scoped by `dataset_id`. Every store call takes the scope explicitly
(`dataset_id=`) or derives it from a loaded dataset (`ctx=`: any
object whose `dataset` is a [`fiftyone.core.dataset.Dataset`](fiftyone.core.dataset.md#fiftyone.core.dataset.Dataset),
such as an operator’s execution context).

Resolution rules: an explicit `tier` wins; `label_schema` membership defaults a field
to `annotate`; `annotate` without content degrades to `explore`;
`hidden` (and a `hidden` default expanded over the dataset universe)
feeds the silent field-exclusion channel. Attribute tiers mask
attributes at resolution; `bbox`/`label` content knobs stamp the
geometry/class-input locks the App applies.

The dataset DEFAULT schema is not a document: [`synthesize_default()`](#fiftyone.core.label_schema_docs.synthesize_default)
builds it from the dataset’s own stored schemas (content fields
annotatable, everything else explore) and it is never persisted.

Copyright 2017-2026, Voxel51, Inc.
<br/>
[voxel51.com](https://voxel51.com/)
<br/>
<br/>

**Data:**

| [`COLLECTION`](#fiftyone.core.label_schema_docs.COLLECTION)                         | Mongo collection holding the documents (dataset-scoped by `dataset_id`).                                                                         |
|-------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| [`MAX_LABEL_SCHEMA_BYTES`](#fiftyone.core.label_schema_docs.MAX_LABEL_SCHEMA_BYTES) | Upper bound on a document's serialized `label_schema` content.                                                                                   |
| [`PROTECTED_PATHS`](#fiftyone.core.label_schema_docs.PROTECTED_PATHS)               | Required/default sample and frame fields a schema can NEVER hide.                                                                                |
| [`PROTECTED_ATTRIBUTES`](#fiftyone.core.label_schema_docs.PROTECTED_ATTRIBUTES)     | identity (`id`), tagging (`tags`), instance linking (`index`) and the geometry the renderer needs.                                               |
| [`LABEL_LIST_KEYS`](#fiftyone.core.label_schema_docs.LABEL_LIST_KEYS)               | hidden ATTRIBUTE values are excluded from sample payloads at `<field>.<list_key>.<attr>` for list types and `<field>.<attr>` for singular types. |

**Functions:**

| [`is_protected`](#fiftyone.core.label_schema_docs.is_protected)(path[, protected])                 | Whether a schema can never hide `path`: it is in `protected` ([`protected_paths()`](#fiftyone.core.label_schema_docs.protected_paths)) or nested under a protected field, like `metadata.width` or `group.name`.                                                                                      |
|----------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`resolve_dataset_id`](#fiftyone.core.label_schema_docs.resolve_dataset_id)(\*[, ctx, dataset_id]) | The dataset ObjectId that scopes a call: `dataset_id` when given, else the id of `ctx.dataset`.                                                                                                                                                                                                       |
| [`snapshot_content`](#fiftyone.core.label_schema_docs.snapshot_content)(dataset)                   | Today's stored per-field label schemas, copied verbatim.                                                                                                                                                                                                                                              |
| [`protected_paths`](#fiftyone.core.label_schema_docs.protected_paths)(dataset)                     | The paths no schema can hide on `dataset`: [`PROTECTED_PATHS`](#fiftyone.core.label_schema_docs.PROTECTED_PATHS) plus its group field and the group's `id` and `name`, which tie a group dataset's slices together.                                                                                   |
| [`schema_universe`](#fiftyone.core.label_schema_docs.schema_universe)(dataset)                     | The dataset's top-level field paths (sample fields, plus `frames.`-prefixed frame fields of a video dataset or of a group dataset's video slices), minus protected paths ([`protected_paths()`](#fiftyone.core.label_schema_docs.protected_paths)) — what a `hidden` visibility default expands over. |
| [`normalize_visibility`](#fiftyone.core.label_schema_docs.normalize_visibility)(raw)               | Validated copy of a structured visibility block; invalid entries dropped.                                                                                                                                                                                                                             |
| [`validate_label_schema`](#fiftyone.core.label_schema_docs.validate_label_schema)(raw)             | The content block a doc may store: a mapping of field path to a mapping (today's per-field label schema entry shape), JSON-serializable and no larger than [`MAX_LABEL_SCHEMA_BYTES`](#fiftyone.core.label_schema_docs.MAX_LABEL_SCHEMA_BYTES).                                                       |
| [`create`](#fiftyone.core.label_schema_docs.create)(\*, name[, description, label_schema, ...])    | Creates a schema doc; raises `ValueError` on a duplicate name or invalid content.                                                                                                                                                                                                                     |
| [`list_`](#fiftyone.core.label_schema_docs.list_)(\*[, ctx, dataset_id])                           | `[{id, name, description, updated_at, version}]` for the dataset.                                                                                                                                                                                                                                     |
| [`get`](#fiftyone.core.label_schema_docs.get)(doc_id, \*[, ctx, dataset_id])                       | The full public doc (`label_schema` + `visibility`), or `None`.                                                                                                                                                                                                                                       |
| [`update`](#fiftyone.core.label_schema_docs.update)(doc_id, \*[, name, description, ...])          | Partial update; returns the updated public doc or `None` when it does not exist.                                                                                                                                                                                                                      |
| [`propagate_field`](#fiftyone.core.label_schema_docs.propagate_field)(path[, entry, ...])          | Propagates a newly created dataset field across every custom schema of the dataset: the schema it was created in (`source_doc_id`) receives `entry` as annotate-tier content; every OTHER schema gets an explicit `hidden` tier for it.                                                               |
| [`delete`](#fiftyone.core.label_schema_docs.delete)(doc_id, \*[, ctx, dataset_id])                 | Deletes a doc; `True` when a document was removed.                                                                                                                                                                                                                                                    |
| [`resolve`](#fiftyone.core.label_schema_docs.resolve)(doc, universe[, protected])                  | Resolves a schema doc into the render payload.                                                                                                                                                                                                                                                        |
| [`synthesize_default`](#fiftyone.core.label_schema_docs.synthesize_default)(dataset)               | The virtual "dataset default" doc: the dataset's own stored schemas as content (annotate by membership), everything else explore.                                                                                                                                                                     |

### fiftyone.core.label_schema_docs.COLLECTION *= 'label_schemas'*

Mongo collection holding the documents (dataset-scoped by `dataset_id`).

### fiftyone.core.label_schema_docs.MAX_LABEL_SCHEMA_BYTES *= 1048576*

Upper bound on a document’s serialized `label_schema` content.

### fiftyone.core.label_schema_docs.PROTECTED_PATHS *= frozenset({'created_at', 'filepath', 'frames', 'frames.created_at', 'frames.frame_number', 'frames.id', 'frames.last_modified_at', 'id', 'last_modified_at', 'media_reference', 'metadata', 'tags'})*

Required/default sample and frame fields a schema can NEVER hide.
The exclusion stage rides with `_allow_missing` (which skips
`ExcludeFields.validate`), and stripping e.g. `filepath` from
sample docs crashes the server’s sample serialization outright.
Their children are protected too ([`is_protected()`](#fiftyone.core.label_schema_docs.is_protected)): hiding e.g.
`metadata.width` makes the server re-read every sample’s media for
its dimensions, and a failed read renders it square at 30 fps.

### fiftyone.core.label_schema_docs.is_protected(path: str, protected: frozenset = frozenset({'created_at', 'filepath', 'frames', 'frames.created_at', 'frames.frame_number', 'frames.id', 'frames.last_modified_at', 'id', 'last_modified_at', 'media_reference', 'metadata', 'tags'})) → [bool](fiftyone.core.stages.md#fiftyone.core.stages.Exists.bool)

Whether a schema can never hide `path`: it is in `protected`
([`protected_paths()`](#fiftyone.core.label_schema_docs.protected_paths)) or nested under a protected field, like
`metadata.width` or `group.name`. Fields under `frames` are
only protected when listed themselves.

### fiftyone.core.label_schema_docs.PROTECTED_ATTRIBUTES *= frozenset({'bounding_box', 'id', 'index', 'mask', 'mask_path', 'points', 'tags'})*

identity (`id`), tagging
(`tags`), instance linking (`index`) and the geometry the
renderer needs. A stored `hidden` tier on one of these normalizes
to `annotate`.

* **Type:**
  Label attributes a schema can never hide

### fiftyone.core.label_schema_docs.LABEL_LIST_KEYS *= {'classifications': 'classifications', 'detections': 'detections', 'keypoints': 'keypoints', 'polylines': 'polylines', 'temporaldetections': 'detections'}*

hidden ATTRIBUTE values are
excluded from sample payloads at `<field>.<list_key>.<attr>` for
list types and `<field>.<attr>` for singular types.

* **Type:**
  Label-list db keys per content type

### fiftyone.core.label_schema_docs.resolve_dataset_id(, ctx=None, dataset_id=None) → [ObjectId](https://pymongo.readthedocs.io/en/stable/api/bson/objectid.html#bson.objectid.ObjectId)

The dataset ObjectId that scopes a call: `dataset_id` when
given, else the id of `ctx.dataset`.

### fiftyone.core.label_schema_docs.snapshot_content(dataset) → dict

Today’s stored per-field label schemas, copied verbatim.

The seed for “New schema from dataset fields”: every stored field
schema becomes doc content (= annotate tier by membership).
Best-effort `{}` on any failure.

### fiftyone.core.label_schema_docs.protected_paths(dataset) → frozenset

The paths no schema can hide on `dataset`: [`PROTECTED_PATHS`](#fiftyone.core.label_schema_docs.PROTECTED_PATHS)
plus its group field and the group’s `id` and `name`, which tie a
group dataset’s slices together.

* **Parameters:**
  **dataset** – a [`fiftyone.core.dataset.Dataset`](fiftyone.core.dataset.md#fiftyone.core.dataset.Dataset), or `None`
* **Returns:**
  a frozenset of paths

### fiftyone.core.label_schema_docs.schema_universe(dataset) → tuple

The dataset’s top-level field paths (sample fields, plus
`frames.`-prefixed frame fields of a video dataset or of a group
dataset’s video slices), minus protected paths
([`protected_paths()`](#fiftyone.core.label_schema_docs.protected_paths)) — what a `hidden` visibility default
expands over.

The universe must be the dataset’s ACTUAL fields: stored
label-schema entries only exist for fields someone configured for
annotation, so expanding over them silently missed every other
field (a default-hidden schema left `segmentations` et al fully
visible on datasets with no stored schemas). Stored entries remain
the fallback when the field schema is unavailable. Protected paths
never enter (a born-hidden schema once excluded `filepath` via a
stale stored entry and crashed sample serialization); any failure
yields an empty universe, which only narrows wildcard expansion.

### fiftyone.core.label_schema_docs.normalize_visibility(raw: Any) → dict

Validated copy of a structured visibility block; invalid entries
dropped.

### fiftyone.core.label_schema_docs.validate_label_schema(raw: Any) → dict

The content block a doc may store: a mapping of field path to a
mapping (today’s per-field label schema entry shape), JSON-serializable
and no larger than [`MAX_LABEL_SCHEMA_BYTES`](#fiftyone.core.label_schema_docs.MAX_LABEL_SCHEMA_BYTES). Raises `ValueError`
otherwise.

### fiftyone.core.label_schema_docs.create(, name: str, description: str = '', label_schema: Mapping | None = None, visibility: Mapping | None = None, created_by: str = '', ctx=None, dataset_id=None) → dict

Creates a schema doc; raises `ValueError` on a duplicate name or
invalid content.

### fiftyone.core.label_schema_docs.list_(, ctx=None, dataset_id=None) → [list](fiftyone.core.session.events.md#fiftyone.core.session.events.Colorscale.list)[dict]

`[{id, name, description, updated_at, version}]` for the dataset.

### fiftyone.core.label_schema_docs.get(doc_id: str, , ctx=None, dataset_id=None) → dict | None

The full public doc (`label_schema` + `visibility`), or `None`.

### fiftyone.core.label_schema_docs.update(doc_id: str, , name: str | None = None, description: str | None = None, label_schema: Mapping | None = None, visibility: Mapping | None = None, expected_version: int | None = None, ctx=None, dataset_id=None) → dict | None

Partial update; returns the updated public doc or `None` when it
does not exist.

`expected_version` makes the write conditional: when the stored
doc’s `version` differs (someone else saved since this caller
loaded it), nothing is written and `ValueError` is raised.

### fiftyone.core.label_schema_docs.propagate_field(path: str, entry: Mapping | None = None, source_doc_id: str | None = None, , ctx=None, dataset_id=None) → int

Propagates a newly created dataset field across every custom
schema of the dataset: the schema it was created in (`source_doc_id`)
receives `entry` as annotate-tier content; every OTHER schema gets
an explicit `hidden` tier for it. Schemas that already model the
field (content or an explicit tier) are left untouched. The dataset
default (the dataset’s own stored schemas) is written by the field
creation itself, not here. Returns the number of docs updated.

### fiftyone.core.label_schema_docs.delete(doc_id: str, , ctx=None, dataset_id=None) → [bool](fiftyone.core.stages.md#fiftyone.core.stages.Exists.bool)

Deletes a doc; `True` when a document was removed.

### fiftyone.core.label_schema_docs.resolve(doc: Mapping, universe: Iterable[str], protected: Iterable[str] | None = None) → dict

Resolves a schema doc into the render payload.

Returns `{id, name, label_schemas, active, excluded_paths,
excluded_attr_paths, excluded_attr_db_paths}` where
`label_schemas` is the `get_label_schemas`-envelope meta map the
Annotate sidebar renders from, `active` is the annotate-tier field
list, and the `excluded_*` lists feed the silent Explore exclusion
channels. `universe` (the dataset’s field paths) expands a
`hidden` default. `protected` ([`protected_paths()`](#fiftyone.core.label_schema_docs.protected_paths), default
[`PROTECTED_PATHS`](#fiftyone.core.label_schema_docs.PROTECTED_PATHS)) are never hidden.

### fiftyone.core.label_schema_docs.synthesize_default(dataset) → dict

The virtual “dataset default” doc: the dataset’s own stored
schemas as content (annotate by membership), everything else
explore. A dataset with no stored schemas yields the empty
permissive doc. Never persisted — run it through [`resolve()`](#fiftyone.core.label_schema_docs.resolve)
like any stored doc.
