NCP-OUSD common mistakes
NCP-OUSD · Understand the traps and how to avoid them.
Treats the composed stage as if it were the raw content of a single layer, so answers about what a prim's value is ignore opinions contributed by sublayers, references, payloads, and variants.
Candidates learn Sdf authoring first and read a single .usda file in a text editor, so they conflate 'what the layer says' with 'what the stage resolves to'. Composition arcs are evaluated lazily and are invisible in the authored file, so the mental model stays layer-local.
What to do instead
For any value question, walk the composition order explicitly: local opinions, sublayers (strongest first), then references/payloads, then variants, then the fallback in the schema. Practice by authoring a prim with a value in a reference and a conflicting local override, then use Usd.Prim.GetPropertyStack or Usd.PrimCompositionQuery to print the actual opinion stack and confirm which wins.
Assumes the strongest layer in the root layer stack always wins, forgetting that LIVRPS ordering places direct local opinions above references regardless of which layer file they live in.
The root layer stack feels like the 'main' file, so candidates apply a simple 'closer to the root file = stronger' heuristic. LIVRPS (Local, Inherits, VariantSets, References, Payloads, Specializes) is a per-prim-index rule, not a file-location rule, and direct opinions on a referenced prim still beat weaker arcs even when authored deeper in the asset.
What to do instead
Memorize LIVRPS as an ordered list and reason about 'where in the arc chain does this opinion sit for this prim index', not 'which file is it in'. Build a two-layer test: root layer with a reference to a child asset that also has a local opinion on the same prim, then verify with Usd.PrimCompositionQuery which node supplies the resolved value.
Confuses the schema class hierarchy with the applied API schema mechanism, answering that a prim 'is a' UsdGeomXformable because it has an xformOp, or expecting a typed schema to be assignable at runtime.
IsA schemas are fixed by the prim's typeName at authoring time, while API schemas (single- and multiple-apply) are applied and removed dynamically and are queried with HasAPI, not IsA. Candidates who only read prim.typeName miss the applied-schema layer entirely.
What to do instead
Learn the two axes separately: typed schemas via GetTypeName/IsA and applied API schemas via HasAPI/GetAppliedSchemas. When writing a custom schema, decide deliberately whether the concept is a new prim type (IsA) or a capability bolted onto existing prims (API schema), and test both with Usd.Prim.IsA and Usd.Prim.HasAPI in a small script.
Writes a custom schema plugin but forgets to register it, so the typeName falls back to a typeless prim and no fallback values or API behaviour appear on the stage.
Schema generation produces C++ and Python wrappers plus plugInfo.json, and the plugInfo must be discoverable on PXR_PLUGINPATH_NAME (or installed into the resource path). Without registration, USD silently treats the unknown type as untyped rather than erroring, so the failure is quiet.
What to do instead
After generating a schema, verify registration before debugging anything else: check that plugInfo.json is on PXR_PLUGINPATH_NAME, run a script that calls Usd.SchemaRegistry.GetTypeFromSchemaTypeName on your typeName, and confirm Usd.Prim.IsA returns true. If it returns false, the plugin is not loaded, not the schema logic.
Treats the scene index as a mutable scene graph and tries to edit prims through it, or assumes Hydra re-reads the USD stage on every frame.
Hydra 2.0's retained scene index is a read-only, notice-driven snapshot built from the stage; changes flow as Sdf/Hydra notices that invalidate specific prims. Candidates coming from immediate-mode renderers expect to poke at render state directly and are surprised when edits do not appear or when the index is not writable.
What to do instead
Model the flow as stage edit to notice to scene index invalidation to render delegate sync. When debugging a stale render, first confirm a notice was emitted (e.g. via a notice listener or Tf.Debug) and that the scene index received an invalidation for the right prim path, rather than assuming the render delegate is broken.
Assumes all interchange formats round-trip USD semantics losslessly, expecting instancing, variants, or composition arcs to survive an export to a flat format unchanged.
Formats like glTF, FBX, and Alembic carry geometry and transforms but not USD's composition or schema metadata; exporters flatten or bake. Candidates who test only geometry see a clean round-trip and generalize that to the whole scene description.
What to do instead
Before answering an interchange question, classify what is being moved: geometry and transforms, material bindings, hierarchy and instancing, or composition and variants. For anything beyond geometry, verify by exporting and re-importing a test asset that deliberately contains a reference and an instance, then inspect what survived rather than assuming.
Builds an asset with absolute asset paths or hard-coded filesystem locations in references and texture inputs, so it works on the authoring machine and fails everywhere else.
The asset resolver resolves relative paths against the anchoring layer, but absolute paths bypass that and bind to one machine's layout. Candidates test only locally and never exercise the resolver under a different search path.
What to do instead
Author references and asset-valued attributes as paths relative to the anchoring layer, and keep the asset self-contained under a single root. Validate by copying the asset directory to a new location and opening it there, and by checking that no authored asset path starts with a drive letter or root slash.
Expects instancing to reduce authoring effort as well as memory, and is surprised when per-instance overrides do not apply or when a prototype cannot be edited directly.
Point instancing and native instancing share a single prototype; only a limited set of opinions (such as transforms and some instanceable-allowed attributes) can vary per instance, and the prototype is not addressable as a normal prim in the stage namespace. Candidates assume instances behave like independent copies.
What to do instead
Decide first whether the requirement is memory (instancing is appropriate) or per-copy variation (it is not, or needs a different decomposition). For native instancing, confirm the prim is marked instanceable and that shared children live under the prototype; for point instancing, use per-instance primvars rather than trying to override prototype children.
Debugs a validation failure by editing the exported or flattened result instead of the source layer that authored the offending opinion, so the problem returns on the next export.
Validators report composed-stage paths and values, which look like they belong to the final asset. The actual opinion may come from a sublayer, a referenced asset, or a variant, and patching the flattened output discards the fix on regeneration.
What to do instead
For every validation error, resolve the owning layer and spec path before editing, using the property stack or a composition query to find which layer authored the value. Fix the source layer, then re-run the validator on a freshly composed stage to confirm the error is gone and no new ones appeared.
Diagnoses a missing or wrong value by guessing at composition order instead of querying the stage, and never checks whether a payload was even loaded.
Payloads are unloaded by default in some contexts and loaded on demand, so a prim can exist structurally while its payloaded content is absent. Without an explicit query, candidates attribute the missing value to layer strength rather than to load state.
What to do instead
Adopt a fixed diagnostic order: confirm the prim exists and its payload load state with Usd.Prim.IsLoaded and GetPrimStack, then print the full composition query and property stack, then check variant selections with GetVariantSets. Only after those three checks should you reason about layer strength.