stride3d/stride · error · ArgumentOutOfRangeException
Type vertex can't be a byte
Error message
Type vertex can't be a byte
What it means
The generic overload GenerateTangentBinormal<T> only supports unmanaged vertex structs with a meaningful layout; T == byte is rejected with ArgumentOutOfRangeException because byte gives stride 1 and no way to interpret vertex semantics.
Solutions
- Define or use a proper vertex struct (e.g. PositionNormalTexture) and cast/copy the bytes into T[] before calling.
- Use the non-generic overload taking IntPtr, vertexCount, and vertexStride instead of the generic byte invocation.
- Use VertexHelper.Convert / BytesToTypedArray-style conversion utilities to reinterpret the data.
Example fix
// before byte[] raw = mesh.GetVertexBytes(); var result = VertexHelper.GenerateTangentBinormal(declaration, raw, indexBuffer); // after var verts = new PositionNormalTexture[raw.Length / declaration.VertexStride]; Buffer.BlockCopy(raw, 0, verts, 0, raw.Length); var result = VertexHelper.GenerateTangentBinormal(declaration, verts, indexBuffer);
Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof(T) == typeof(byte))
throw new InvalidOperationException("Convert raw bytes to a vertex struct before calling GenerateTangentBinormal"); Type guard
bool IsSupportedVertexType<T>() where T : unmanaged => typeof(T) != typeof(byte);
Try / catch
try { var result = VertexHelper.GenerateTangentBinormal(decl, data, indices); }
catch (ArgumentOutOfRangeException ex) { log.Error("Unsupported vertex element type; use a real vertex struct", ex); } Prevention
- Keep vertex data typed as dedicated structs, not byte[]
- Convert raw bytes with Buffer.BlockCopy into T[] before transforms
- Use the IntPtr overload for opaque native data instead of T=byte
When it happens
Trigger: Calling VertexHelper.GenerateTangentBinormal<byte>(declaration, rawBytes, indexBuffer) — typically when holding the vertex data as a raw byte array copied from a buffer.
Common situations: Reading vertex data back from a GPU buffer into byte[] then passing it straight into the generic API; serializing code paths that treat vertex data as opaque bytes.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Cannot copy data between GraphicsResources of types
- Expecting a type inheriting from…
- Expecting a type inheriting from…
- Invalid sizeof(T), not a multiple of current size
- Unknown resource type
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/068163659f472e50.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Graphics/VertexHelper.cs:209
var allVertexElements = new List<VertexElement>(vertexDeclaration.VertexElements);
allVertexElements.AddRange(newVertexElements);
return new VertexTransformResult(new VertexDeclaration(allVertexElements.ToArray()), newVertexBuffer);
}
/// <summary>
/// Generates the tangent binormal for an existing vertex buffer.
/// </summary>
/// <param name="vertexDeclaration">The vertex declaration.</param>
/// <param name="vertexBufferData">The vertex buffer data.</param>
/// <param name="indexBuffer">The index buffer.</param>
/// <returns>A new vertex buffer with its new layout.</returns>
public static unsafe VertexTransformResult GenerateTangentBinormal<T>(VertexDeclaration vertexDeclaration, T[] vertexBufferData, int[] indexBuffer) where T : unmanaged
{
if (vertexDeclaration == null) throw new ArgumentNullException("vertexDeclaration");
if (vertexBufferData == null) throw new ArgumentNullException("vertexBufferData");
if (typeof(T) == typeof(byte)) throw new ArgumentOutOfRangeException("T", "Type vertex can't be a byte");
var vertexStride = Unsafe.SizeOf<T>();
fixed (void* vertexBufferPtr = vertexBufferData)
fixed (void* indexBufferPtr = indexBuffer)
{
return GenerateTangentBinormal(vertexDeclaration, (nint)vertexBufferPtr, vertexBufferData.Length, 0, vertexStride, (nint)indexBufferPtr, true, indexBuffer?.Length ?? 0);
}
}
/// <summary>
/// Generate Tangent BiNormal from an existing vertex/index buffer.
/// </summary>
/// <param name="vertexDeclaration">The vertex declaration of the vertex buffer passed by parameters.</param>
/// <param name="vertexBufferData">The vertex buffer.</param>
/// <param name="vertexCount">The vertex count.</param>
/// <param name="vertexOffset">The vertex offset.</param>
/// <param name="vertexStride">The vertex stride. If 0, It takes the stride from the vertex declaration</param>
/// <param name="indexData">The index data.</param>View on GitHub (pinned to 96fad776d2)