{"record":{"id":"eeb36e598553aa7c","repo":"stride3d/stride","slug":"trying-to-serialize-a-texture-without-cpu-info-eeb36e","errorCode":null,"errorMessage":"Trying to serialize a Texture without CPU info.","messagePattern":"Trying to serialize a Texture without CPU info\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Graphics/Data/TextureImageSerializer.cs","lineNumber":52,"sourceCode":"                    var contentSerializerContext = stream.Context.Get(ContentSerializerContext.ContentSerializerContextProperty);\n                    if (contentSerializerContext != null)\n                    {\n                        texture.Reload = static (graphicsResource, services) =>\n                        {\n                            var assetManager = services.GetService<ContentManager>();\n                            assetManager.TryGetAssetUrl(graphicsResource, out var url);\n                            var textureDataReloaded = assetManager.Load<Image>(url);\n                            ((Texture)graphicsResource).Recreate(textureDataReloaded.ToDataBox());\n                            assetManager.Unload(textureDataReloaded);\n                        };\n                    }\n                }\n            }\n            else\n            {\n                var textureData = texture.GetSerializationData();\n                if (textureData == null)\n                    throw new InvalidOperationException(\"Trying to serialize a Texture without CPU info.\");\n\n                textureData.Image.Save(stream.UnderlyingStream, ImageFileType.Stride);\n            }\n        }\n\n        public override object Construct(ContentSerializerContext context)\n        {\n            return new Texture();\n        }\n    }\n}\n","sourceCodeStart":34,"sourceCodeEnd":64,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Graphics/Data/TextureImageSerializer.cs#L34-L64","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Serialize the original Texture asset (which has CPU image data) instead of a runtime/GPU-created texture","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","Recreate/compile the texture with CPU serialization data enabled (TextureFlags none / serializable asset import)","If you own the code, guard with if (texture.GetSerializationData() == null) and use an alternative export path"],"exampleFix":"// before\nserializer.Save(stream, gpuRenderTarget); // no CPU info -> throws\n// after\nvar staging = Texture.New2D(device, tex.Width, tex.Height, tex.Format, TextureFlags.Staging);\ncontext.CommandList.Copy(tex, staging);\nvar image = staging.GetDataAsImage(context.CommandList);\nimage.Save(fileStream, ImageFileType.Png);","handlingStrategy":"type-guard","validationCode":"if (texture.GetSerializationData()?.Image == null)\n{\n    // fall back to staging-texture readback path instead of content serializer\n}","typeGuard":"bool CanSerialize(Texture t) => t.GetSerializationData() != null;","tryCatchPattern":"try\n{\n    serializer.Save(stream, texture);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"without CPU info\"))\n{\n    SaveViaStagingReadback(texture);\n}","preventionTips":["Only serialize texture assets compiled with CPU image data","Never route render targets / GPU-only textures through TextureImageSerializer","Use staging-texture readback for runtime captures"],"tags":["graphics","texture","serialization"],"backgroundTag":"null-argument","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}