{"record":{"id":"b58af7e4a14949ec","repo":"stride3d/stride","slug":"invalid-texture-used-as-staging-resource-it-must-have","errorCode":null,"errorMessage":"Invalid Texture used as staging Resource. It must have GraphicsResourceUsage.Staging","messagePattern":"Invalid Texture used as staging Resource\\. It must have GraphicsResourceUsage\\.Staging","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Graphics/Texture.cs","lineNumber":1729,"sourceCode":"            return GetDataAsImage(commandList, stagingTexture);\n        }\n\n        /// <summary>\n        ///   Gets the contents of the Texture on GPU memory to an <see cref=\"Image\"/> on the CPU.\n        /// </summary>\n        /// <param name=\"commandList\">The <see cref=\"CommandList\"/> where to register the command.</param>\n        /// <param name=\"stagingTexture\">\n        ///   The staging Texture used to temporarily transfer the image from GPU memory to CPU memory.\n        /// </param>\n        /// <exception cref=\"ArgumentException\"><paramref name=\"stagingTexture\"/> is not a staging Texture.</exception>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"stagingTexture\"/> is <see langword=\"null\"/>.</exception>\n        /// <returns>The Image on CPU memory.</returns>\n        public unsafe Image GetDataAsImage(CommandList commandList, Texture stagingTexture)\n        {\n            ArgumentNullException.ThrowIfNull(stagingTexture);\n\n            if (stagingTexture.Usage != GraphicsResourceUsage.Staging)\n                throw new ArgumentException(\"Invalid Texture used as staging Resource. It must have GraphicsResourceUsage.Staging\", nameof(stagingTexture));\n\n            var image = Image.New(stagingTexture.Description);\n            try\n            {\n                for (int arrayIndex = 0; arrayIndex < image.Description.ArraySize; arrayIndex++)\n                {\n                    for (int mipLevel = 0; mipLevel < image.Description.MipLevels; mipLevel++)\n                    {\n                        var pixelBuffer = image.PixelBuffer[arrayIndex, mipLevel];\n                        GetData(commandList, stagingTexture, new Span<byte>((byte*) pixelBuffer.DataPointer, pixelBuffer.BufferStride), arrayIndex, mipLevel);\n                    }\n                }\n            }\n            catch\n            {\n                // If there was an exception, free the allocated image to avoid any memory leak\n                image.Dispose();\n                throw;","sourceCodeStart":1711,"sourceCodeEnd":1747,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Graphics/Texture.cs#L1711-L1747","documentation":"Thrown by Texture.GetDataAsImage when the supplied stagingTexture does not have GraphicsResourceUsage.Staging. Reading GPU texture data back to the CPU requires a staging resource that the GPU can copy into and the CPU can map. Any other usage type is rejected with ArgumentException.","triggerScenarios":"Calling GetDataAsImage(commandList, stagingTexture) with a texture created with default Usage (e.g. Immutable or the render-target itself) instead of a dedicated staging texture created via Texture.New2D/3D with GraphicsResourceUsage.Staging.","commonSituations":"Passing the source texture directly instead of creating a staging copy; a helper that used to accept the render target changed API; copy-pasted texture creation missing the usage argument.","solutions":["Create a staging texture: var staging = Texture.New2D(services, width, height, mipLevel: 1, format, TextureFlags.None, usage: GraphicsResourceUsage.Staging); then copy and read from it.","Check stagingTexture.Usage == GraphicsResourceUsage.Staging before calling GetDataAsImage.","If you have an existing texture, commandList.Copy(texture, stagingTexture) into a staging texture first."],"exampleFix":"// before\ntexture.GetDataAsImage(commandList, texture); // source is not staging\n// after\nvar staging = Texture.New2D(services, texture.Width, texture.Height, 1, texture.Format, TextureFlags.None, usage: GraphicsResourceUsage.Staging);\ncommandList.Copy(texture, staging);\nvar image = texture.GetDataAsImage(commandList, staging);","handlingStrategy":"validation","validationCode":"if (stagingTexture == null || stagingTexture.Usage != GraphicsResourceUsage.Staging)\n    throw new InvalidOperationException(\"GetDataAsImage requires a GraphicsResourceUsage.Staging texture\");","typeGuard":"bool IsStaging(Texture t) => t is not null && t.Usage == GraphicsResourceUsage.Staging;","tryCatchPattern":"try { var img = texture.GetDataAsImage(cmd, staging); }\ncatch (ArgumentException e) when (e.ParamName == \"stagingTexture\") { log.Error(\"Readback texture must be Staging\", e); }","preventionTips":["Always create readback textures with GraphicsResourceUsage.Staging.","Keep one reusable staging texture per format/size.","Assert Usage before every GPU readback."],"tags":["graphics","invalid-argument-value","gpu-readback"],"backgroundTag":"invalid-argument-value","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"}