stride3d/stride · error · InvalidOperationException

The camera [ ] isn't attached

Error message

The camera [{camera.Entity.Name}] isn't attached

What it means

DetachCameraFromSlot throws InvalidOperationException when the given CameraComponent's Slot has no AttachedCompositor, meaning the camera is not currently attached anywhere and thus cannot be detached.

Solutions

  1. Check camera.Slot?.AttachedCompositor != null before detaching
  2. Ensure the detach path is idempotent: skip instead of throwing when not attached
  3. Don't change camera.Slot while it is attached; detach first, then reassign
  4. If removing an entity, verify the camera went through the attach path in this processor

Example fix

// before
cameraProcessor.DetachCameraFromSlot(camera);
// after
if (camera.Slot.AttachedCompositor != null)
    cameraProcessor.DetachCameraFromSlot(camera);
Defensive patterns

Strategy: type-guard

Validate before calling

if (camera.Slot?.AttachedCompositor == null) return; // nothing to detach

Type guard

bool CanDetach(CameraComponent c) => c?.Slot?.AttachedCompositor != null;

Try / catch

try { DetachCameraFromSlot(camera); }
catch (InvalidOperationException ex) when (ex.Message.Contains("isn't attached")) { /* already detached; ignore */ }

Prevention

When it happens

Trigger: Calling detach logic (via the Draw pass or OnEntityComponentRemoved) on a camera whose Slot.AttachedCompositor is null: it was never attached, was already detached, or its Slot was changed while attached.

Common situations: Removing a camera entity from a scene that was never attached; double-detach; reassigning camera.Slot (nulls/replaces attachment state) then removing the entity; disabling cameras and assuming detach is always safe.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/13c3015538b05f04. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Engine/Engine/Processors/CameraProcessor.cs:152

            for (var i = 0; i < graphicsCompositor.Cameras.Count; ++i)
            {
                var slot = graphicsCompositor.Cameras[i];
                if (slot.Id == camera.Slot.Id)
                {
                    if (slot.Camera != null)
                        throw new InvalidOperationException($"Unable to attach camera [{camera.Entity.Name}] to the graphics compositor. Another camera, [{slot.Camera.Entity.Name}], is enabled and already attached to this slot.");

                    slot.Camera = camera;
                    camera.Slot.AttachedCompositor = graphicsCompositor;
                    break;
                }
            }
        }

        private static void DetachCameraFromSlot(CameraComponent camera)
        {
            if (camera.Slot.AttachedCompositor == null)
                throw new InvalidOperationException($"The camera [{camera.Entity.Name}] isn't attached");

            for (var i = 0; i < camera.Slot.AttachedCompositor.Cameras.Count; ++i)
            {
                var slot = camera.Slot.AttachedCompositor.Cameras[i];
                if (slot.Id == camera.Slot.Id)
                {
                    if (slot.Camera != camera)
                        throw new InvalidOperationException($"Can'to detach camera [{camera.Entity.Name}] from the graphics compositor. Another camera, {slot.Camera.Entity.Name}, is attached to this slot.");

                    slot.Camera = null;
                    break;
                }
            }
            camera.Slot.AttachedCompositor = null;
        }

        private static void DetachCameraFromAllSlots(CameraComponent camera, GraphicsCompositor graphicsCompositor)
        {

View on GitHub (pinned to 96fad776d2)