{"record":{"id":"157a21834f8bf2bf","repo":"stride3d/stride","slug":"passthrough-already-started","errorCode":null,"errorMessage":"Passthrough already started","messagePattern":"Passthrough already started","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.VirtualReality/OpenXR/OpenXRHmd.cs","lineNumber":395,"sourceCode":"                Type = StructureType.InteractionProfileState,\n                Next = null\n            };\n            Xr.StringToPath(Instance, \"/user/hand/left\", ref leftHandPath);\n        }\n\n        public override IDisposable StartPassthrough()\n        {\n            if (!passthroughRequested)\n                throw new InvalidOperationException(\"The passthrough mode needs to be enabled at device creation\");\n\n            if (!SupportsPassthrough)\n                throw new NotSupportedException(\"The device does not support passthrough mode\");\n\n            if (passthroughExt is null)\n                passthroughExt = new OpenXRExt_FB_Passthrough(Xr, globalSession, Instance);\n\n            if (passthroughExt.Enabled)\n                throw new InvalidOperationException(\"Passthrough already started\");\n\n            passthroughExt.Enabled = true;\n\n            return new AnonymousDisposable(() => passthroughExt.Enabled = false);\n        }\n\n        private void EndNullFrame()\n        {\n            FrameEndInfo frame_end_info = new FrameEndInfo()\n            {\n                Type = StructureType.FrameEndInfo,\n                DisplayTime = globalFrameState.PredictedDisplayTime,\n                EnvironmentBlendMode = EnvironmentBlendMode.Opaque,\n                LayerCount = 0,\n                Layers = null,\n                Next = null\n            };\n            Xr.EndFrame(globalSession, frame_end_info).CheckResult();","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.VirtualReality/OpenXR/OpenXRHmd.cs#L377-L413","documentation":"StartPassthrough() throws this InvalidOperationException when the FB passthrough extension instance reports it is already Enabled. Each device can have only one active passthrough session; starting a second one would conflict with the first. Callers should keep the IDisposable returned by StartPassthrough and dispose it to stop passthrough before starting again.","triggerScenarios":"Calling StartPassthrough() twice without disposing the IDisposable returned by the first call; storing the first disposable but calling StartPassthrough again on a later frame.","commonSituations":"Double initialization from both a scene script and a game-loop update; re-entering a VR scene that starts passthrough each time without stopping the previous session; missing ownership tracking of the returned disposable.","solutions":["Keep the IDisposable from StartPassthrough and dispose it before calling StartPassthrough again.","Track a bool/nullable field so StartPassthrough is only invoked when no passthrough session is active.","Wrap StartPassthrough in a check (or a try/catch for InvalidOperationException) to make starting idempotent."],"exampleFix":"// before\npassthrough = hmd.StartPassthrough(); // called every frame, throws once enabled\n// after\npassthrough ??= hmd.StartPassthrough(); // start once, dispose to stop\n// or:\nif (passthrough == null) passthrough = hmd.StartPassthrough();","handlingStrategy":"type-guard","validationCode":"if (activePassthrough != null) return; // already started\ncurrentPassthrough = hmd.StartPassthrough();","typeGuard":"bool PassthroughActive(IDisposable? session) => session != null;","tryCatchPattern":"try { passthrough = hmd.StartPassthrough(); }\ncatch (InvalidOperationException) { /* already started; reuse existing session */ }","preventionTips":["Store the IDisposable returned by StartPassthrough and dispose before restarting.","Use null-coalescing/once-only initialization for the passthrough session.","Stop passthrough deterministically on scene exit."],"tags":["openxr","vr","passthrough","double-start","invalid-operation"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}