{"record":{"id":"ddb6edf3ff0938b7","repo":"affaan-m/ECC","slug":"resolve-returned-an-item-without-an-identity","errorCode":null,"errorMessage":"Resolve returned an item without an identity","messagePattern":"Resolve returned an item without an identity","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/resolve.py","lineNumber":202,"sourceCode":"                }\n                for item in _items(timeline, kind, track)\n            ]\n    return snapshot\n\n\ndef _readback(timeline, item, event):\n    track = event[\"track\"]\n    members = _items(timeline, \"video\", track)\n\n    # API wrappers can be recreated on each call, so verify track membership by\n    # stable unique id when available; test doubles may use object identity.\n    def identity(candidate):\n        method = getattr(candidate, \"GetUniqueId\", None)\n        return method() if callable(method) else id(candidate)\n\n    item_id = identity(item)\n    if item_id is None:\n        raise RuntimeError(\"Resolve returned an item without an identity\")\n    matches = [member for member in members if identity(member) == item_id]\n    if len(matches) != 1:\n        raise RuntimeError(f\"placement {event['id']} missing from requested track\")\n    item = matches[0]\n    actual = {\n        \"start\": item.GetStart(),\n        \"end\": item.GetEnd(),\n        \"duration\": item.GetDuration(),\n        \"enabled\": item.GetClipEnabled(),\n        \"track\": track,\n        \"opacity\": item.GetProperty(\"Opacity\"),\n        \"composite\": item.GetProperty(\"CompositeMode\"),\n        \"path\": _path(item),\n    }\n    expected = {\n        \"start\": event[\"record_frame\"],\n        \"end\": event[\"record_frame\"] + event[\"frames\"],\n        \"duration\": event[\"frames\"],","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/resolve.py#L184-L220","documentation":"During readback, tasteforge identities each appended clip via GetUniqueId (falling back to id()). If Resolve returns an item whose identity is None, matching it against the placement's members is impossible, so this RuntimeError is raised as an internal invariant violation.","triggerScenarios":"_readback iterating track items where a member's GetUniqueId returns None or is not callable and the object wraps None; Resolve API returning placeholder/invalid clip objects after append.","commonSituations":"Resolve version with changed/removed GetUniqueId behavior returning None; corrupted clip after failed import; API object garbage-collected mid-readback in a long-running session.","solutions":["Upgrade/patch Resolve API usage — check the Resolve/Studio version's API for GetUniqueId support","Re-acquire the timeline and retry after the append settles","Inspect the track items to find the corrupted clip and remove/re-add it","Extend identity() to reject/handle None early with a clearer probe of the item"],"exampleFix":"// before\nmethod = getattr(candidate, \"GetUniqueId\", None)\nreturn method() if callable(method) else id(candidate)\n// after\nmethod = getattr(candidate, \"GetUniqueId\", None)\nuid = method() if callable(method) else None\nif uid is None:\n    raise RuntimeError(f\"item {candidate.GetName() if hasattr(candidate,'GetName') else candidate} has no unique id\")\nreturn uid","handlingStrategy":"try-catch","validationCode":"for item in members:\n    uid = item.GetUniqueId() if callable(getattr(item, \"GetUniqueId\", None)) else None\n    if uid is None:\n        raise RuntimeError(f\"item {item.GetName()} has no unique id\")","typeGuard":"def has_identity(item) -> bool:\n    m = getattr(item, \"GetUniqueId\", None)\n    return callable(m) and m() is not None","tryCatchPattern":"try:\n    result = apply_placements(...)\nexcept RuntimeError as exc:\n    if \"without an identity\" in str(exc):\n        # re-acquire timeline and retry once\n        timeline = project.GetCurrentTimeline()\n    else:\n        raise","preventionTips":["Keep Resolve updated; GetUniqueId behavior varies across versions","Re-acquire timeline objects after appends instead of caching them","Avoid running concurrent API scripts against the same project","Log item names when identity checks fail for easier diagnosis"],"tags":["resolve-api","readback","identity"],"backgroundTag":"internal-invariant-violation","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}