[BUG] LayerStack + List Editing: RemovePayload/SetPayloads Do Not Override Lower‑Reference Payloads

Hello,

When using the UsdPayloads list‑editing API (RemovePayload, SetPayloads) in an override layer, the original payload from a lower reference isn’t removed—both payloads remain active in the final composed stage.

Documentation:

I’m using SetPayloads function which should explicitly replace the payload at the /Scene/payloadA prim. Even force-deleting the payload from a lower comp arc in the layer stack doesn’t seem to work.

How to Reproduce
I’ve attached this reproduction python script will create 5 usda files in the same folder you run it in. I’ve been viewing the resulting stage of Main.usda in usdview. I’m on USD version 24.8.

Any assistance in confirming this bug or finding a workaround would be greatly appreciated.

Best,

–Felipe

from pxr import Usd, UsdGeom, Sdf

# 1. Create PayloadA_ORIG.usda
payloadAStage = Usd.Stage.CreateNew('PayloadA_ORIG.usda')  # Create new stage
payloadARoot = UsdGeom.Xform.Define(payloadAStage, '/payloadA')  # Define default prim path
payloadAStage.SetDefaultPrim(payloadARoot.GetPrim())  # Set defaultPrim = "payloadA"
UsdGeom.Xform.Define(payloadAStage, '/payloadA/payloadA1_1')
UsdGeom.Xform.Define(payloadAStage, '/payloadA/payloadA1_2')
payloadAStage.GetRootLayer().Save()

# 2. Create PayloadA_NEW.usda
newPayloadAStage = Usd.Stage.CreateNew('PayloadA_NEW.usda')  # Create new stage
newPayloadARoot = UsdGeom.Xform.Define(newPayloadAStage, '/payloadA')  # Define default prim path
newPayloadAStage.SetDefaultPrim(newPayloadARoot.GetPrim())  # Set defaultPrim = "payloadA"
UsdGeom.Xform.Define(newPayloadAStage, '/payloadA/new_payloadA1')
UsdGeom.Xform.Define(newPayloadAStage, '/payloadA/new_payloadA2')
UsdGeom.Xform.Define(newPayloadAStage, '/payloadA/new_payloadA3')
newPayloadAStage.GetRootLayer().Save()

# 3. Create BaseLayer.usda
baseStage = Usd.Stage.CreateNew('BaseLayer.usda')  # Create new stage
baseSceneXform = UsdGeom.Xform.Define(baseStage, '/Scene')
basePayloadXform = UsdGeom.Xform.Define(baseStage, '/Scene/payloadA')
basePayloadPrim = baseSceneXform.GetPrim()
payloadPrim = basePayloadXform.GetPrim()
baseStage.SetDefaultPrim(basePayloadPrim)  # Set defaultPrim = "Scene"
basePayload = Sdf.Payload('PayloadA_ORIG.usda')
payloadPrim.GetPayloads().SetPayloads([basePayload])  # Append payload listOp 
baseStage.GetRootLayer().Save()

# 4. Create Override.usda
overrideStage = Usd.Stage.CreateNew('Override.usda')
overrideSceneXform   = UsdGeom.Xform.Define(overrideStage, '/Scene')
overridePayloadXform = UsdGeom.Xform.Define(overrideStage, '/Scene/payloadA')
overrideScenePrim = overrideSceneXform.GetPrim()
overridePayloadPrim = overridePayloadXform.GetPrim()
overrideStage.SetDefaultPrim(overrideScenePrim)  # Set defaultPrim = "Scene"
payloadsAPI = overridePayloadPrim.GetPayloads()

# This call doesn't seem to do anything or create any errors even if you specify a target layer.
payloadsAPI.RemovePayload(Sdf.Payload('PayloadA_ORIG.usda'))

# Set SetPayloads instead of AddPayloads
payloadsAPI.SetPayloads([Sdf.Payload('PayloadA_NEW.usda')])
overrideStage.GetRootLayer().Save()

# 5. Create Main.usda
mainStage = Usd.Stage.CreateNew('Main.usda')
sceneXform = UsdGeom.Xform.Define(mainStage, '/Scene')
scenePrim = sceneXform.GetPrim()
scenePrim.GetReferences().AddReference(
    assetPath='BaseLayer.usda',
    primPath=Sdf.Path()    # reference the defaultPrim of that layer
)

# Set subLayers listOp
mainStage.GetRootLayer().subLayerPaths = ['Override.usda']
mainStage.GetRootLayer().Save()


def forciblyDeletePayload():
    filePath = 'Override.usda'

    # 1. Read all lines
    with open(filePath, 'r') as f:
        lines = f.readlines()

    # 2. Find the index of the NEW-payload line
    targetIndex = None
    for i, line in enumerate(lines):
        if 'payload = @PayloadA_NEW.usda@' in line:
            targetIndex = i
            break

    if targetIndex is None:
        raise RuntimeError("Couldn't find the NEW-payload line in Override.usda")

    # 3. Compute indentation and build insert lines
    indentation = lines[targetIndex][:len(lines[targetIndex]) - len(lines[targetIndex].lstrip())]
    commentLine   = f"{indentation}delete payload = @PayloadA_ORIG.usda@\n"

    # 4. Insert them just before the NEW-payload line
    lines.insert(targetIndex, commentLine)

    # 5. Write back out
    with open(filePath, 'w') as f:
        f.writelines(lines)

# forciblyDeletePayload() # Comment this in to forcebly add the "delete payload = @PayloadA_ORIG.usda@" line
print(f"Usd Version: {Usd.GetVersion()[1]}.{Usd.GetVersion()[2]}")

Would you be able to file an issue against the OpenUSD repo with the contents of your post? It’ll help just officially track it at the very least as something that’s being hit.

Thanks! I’ve added it here:

1 Like