stride3d/stride · error · InvalidOperationException

Trying to serialize a Texture without CPU info.

Error message

Trying to serialize a Texture without CPU info.

What it means

TextureImageSerializer.Serialize throws this InvalidOperationException when serializing a Texture that only exists on the GPU and has no CPU-side serialization data. Texture.GetSerializationData() returns null when the texture was created without CPU-readable data (e.g. render target or GPU-only usage flags), so there is no image to write into the .stride file. The serializer refuses to silently emit an empty/invalid image.

Solutions

  1. Serialize the original Texture asset (which has CPU image data) instead of a runtime/GPU-created texture
  2. Read back GPU data explicitly: render/copy the texture into a staging texture and save that image via Image.Save rather than the content serializer
  3. Recreate/compile the texture with CPU serialization data enabled (TextureFlags none / serializable asset import)
  4. If you own the code, guard with if (texture.GetSerializationData() == null) and use an alternative export path

Example fix

// before
serializer.Save(stream, gpuRenderTarget); // no CPU info -> throws
// after
var staging = Texture.New2D(device, tex.Width, tex.Height, tex.Format, TextureFlags.Staging);
context.CommandList.Copy(tex, staging);
var image = staging.GetDataAsImage(context.CommandList);
image.Save(fileStream, ImageFileType.Png);
Defensive patterns

Strategy: type-guard

Validate before calling

if (texture.GetSerializationData()?.Image == null)
{
    // fall back to staging-texture readback path instead of content serializer
}

Type guard

bool CanSerialize(Texture t) => t.GetSerializationData() != null;

Try / catch

try
{
    serializer.Save(stream, texture);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("without CPU info"))
{
    SaveViaStagingReadback(texture);
}

Prevention

When it happens

Trigger: Calling the content serializer's Serialize on a Texture created with TextureFlags.RenderTarget / GPU-only flags or loaded without the 'serializable' CPU data block, so texture.GetSerializationData() returns null; serializing textures at runtime instead of using assets compiled with CPU data.

Common situations: Trying to save screenshots or render targets via the content serialization path; migrating a runtime-created texture through ContentManager.Save; passing a texture loaded from GPU memory (no staging access) into the image serializer; forgetting to enable CPU-side data when importing textures.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Graphics/Data/TextureImageSerializer.cs:52

                    var contentSerializerContext = stream.Context.Get(ContentSerializerContext.ContentSerializerContextProperty);
                    if (contentSerializerContext != null)
                    {
                        texture.Reload = static (graphicsResource, services) =>
                        {
                            var assetManager = services.GetService<ContentManager>();
                            assetManager.TryGetAssetUrl(graphicsResource, out var url);
                            var textureDataReloaded = assetManager.Load<Image>(url);
                            ((Texture)graphicsResource).Recreate(textureDataReloaded.ToDataBox());
                            assetManager.Unload(textureDataReloaded);
                        };
                    }
                }
            }
            else
            {
                var textureData = texture.GetSerializationData();
                if (textureData == null)
                    throw new InvalidOperationException("Trying to serialize a Texture without CPU info.");

                textureData.Image.Save(stream.UnderlyingStream, ImageFileType.Stride);
            }
        }

        public override object Construct(ContentSerializerContext context)
        {
            return new Texture();
        }
    }
}

View on GitHub (pinned to 96fad776d2)