stride3d/stride · error · InvalidOperationException

The camera [ ] is already attached

Error message

The camera [{camera.Entity.Name}] is already attached

What it means

CameraProcessor.AttachCameraToSlot throws InvalidOperationException when the CameraComponent's Slot already has an AttachedCompositor, i.e. the camera is already bound to some compositor slot. A camera cannot be attached to more than one slot at a time.

Solutions

  1. Check camera.Slot.AttachedCompositor == null before attaching, or skip if already attached
  2. Set camera.Slot.AttachedCompositor = null (detach) before re-attaching elsewhere
  3. Use a separate CameraComponent per slot instead of reusing one instance
  4. Ensure attach logic runs only once (guard with a bool or only on entity add)

Example fix

// before
cameraProcessor.AttachCameraToSlot(compositor, camera);
// after
if (camera.Slot.AttachedCompositor == null)
    cameraProcessor.AttachCameraToSlot(compositor, camera);
Defensive patterns

Strategy: type-guard

Validate before calling

if (camera.Slot?.AttachedCompositor != null) return; // already attached

Type guard

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

Try / catch

try { AttachCameraToSlot(compositor, camera); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already attached")) { /* no-op */ }

Prevention

When it happens

Trigger: Attaching the same CameraComponent twice (e.g. adding the entity again, re-running setup logic each frame, or reusing one camera component across two GraphicsCompositor slots).

Common situations: Re-adding a camera entity to a scene without removing it first; sharing a single camera component between two scene setups; script that calls attach logic every Update instead of once.

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/1b4cad2a850f03af. Report an issue: GitHub.

Appendix: source

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

                }
            }
        }

        protected override void OnEntityComponentRemoved(Entity entity, CameraComponent component, CameraComponent data)
        {
            if (component.Slot.AttachedCompositor != null)
                DetachCameraFromSlot(component);
        }

        private void OnCameraSlotsChanged(object sender, ref FastTrackingCollectionChangedEventArgs e)
        {
            cameraSlotsDirty = true;
        }

        private void AttachCameraToSlot(GraphicsCompositor graphicsCompositor, CameraComponent camera)
        {
            if (!camera.Enabled) throw new InvalidOperationException($"The camera [{camera.Entity.Name}] is disabled and can't be attached");
            if (camera.Slot.AttachedCompositor != null) throw new InvalidOperationException($"The camera [{camera.Entity.Name}] is already attached");

            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)
        {

View on GitHub (pinned to 96fad776d2)