libgdx/libgdx · error · GdxRuntimeException

Can't use + buffer.getClass().getName() + with type + typ

Error message

Can't use  + buffer.getClass().getName() +  with type  + type +  with this method. Use ByteBuffer and one of GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT or GL_FLOAT for type. Blame LWJGL

What it means

Thrown by LwjglGL20.glVertexAttribPointer when a ByteBuffer is bound as the attribute buffer but the type argument is none of GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT or GL_FLOAT. For each accepted type the backend reinterprets the ByteBuffer (asShortBuffer/asFloatBuffer) to satisfy LWJGL's typed overloads; other types — notably GL_UNSIGNED_INT and GL_FIXED — have no desktop overload path, hence 'Blame LWJGL'.

Source

Thrown at backends/gdx-backend-lwjgl/src/com/badlogic/gdx/backends/lwjgl/LwjglGL20.java:836

	public void glVertexAttrib4fv (int indx, FloatBuffer values) {
		GL20.glVertexAttrib4f(indx, values.get(), values.get(), values.get(), values.get());
	}

	public void glVertexAttribPointer (int indx, int size, int type, boolean normalized, int stride, Buffer buffer) {
		if (buffer instanceof ByteBuffer) {
			if (type == GL_BYTE)
				GL20.glVertexAttribPointer(indx, size, false, normalized, stride, (ByteBuffer)buffer);
			else if (type == GL_UNSIGNED_BYTE)
				GL20.glVertexAttribPointer(indx, size, true, normalized, stride, (ByteBuffer)buffer);
			else if (type == GL_SHORT)
				GL20.glVertexAttribPointer(indx, size, false, normalized, stride, ((ByteBuffer)buffer).asShortBuffer());
			else if (type == GL_UNSIGNED_SHORT)
				GL20.glVertexAttribPointer(indx, size, true, normalized, stride, ((ByteBuffer)buffer).asShortBuffer());
			else if (type == GL_FLOAT)
				GL20.glVertexAttribPointer(indx, size, normalized, stride, ((ByteBuffer)buffer).asFloatBuffer());
			else
				throw new GdxRuntimeException("Can't use " + buffer.getClass().getName() + " with type " + type
					+ " with this method. Use ByteBuffer and one of GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT or GL_FLOAT for type. Blame LWJGL");
		} else if (buffer instanceof FloatBuffer) {
			if (type == GL_FLOAT)
				GL20.glVertexAttribPointer(indx, size, normalized, stride, (FloatBuffer)buffer);
			else
				throw new GdxRuntimeException(
					"Can't use " + buffer.getClass().getName() + " with type " + type + " with this method.");
		} else
			throw new GdxRuntimeException(
				"Can't use " + buffer.getClass().getName() + " with this method. Use ByteBuffer instead. Blame LWJGL");
	}

	public void glViewport (int x, int y, int width, int height) {
		GL11.glViewport(x, y, width, height);
	}

	public void glDrawElements (int mode, int count, int type, int indices) {
		GL11.glDrawElements(mode, count, type, indices);

View on GitHub (pinned to 97f4086187)

Solutions

  1. Use GL_FLOAT with a FloatBuffer (or ByteBuffer reinterpreted via asFloatBuffer) for float attribute data — the standard desktop path.
  2. For integer attribute data, upload through an IntBuffer-backed VBO and the int-offset glVertexAttribPointer overload.
  3. Replace GL_FIXED layouts with float layouts on desktop; fixed-point is not a desktop type.

Example fix

// before
Gdx.gl20.glVertexAttribPointer(loc, 4, GL20.GL_UNSIGNED_INT, false, stride, byteBuffer); // throws

// after
Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, vboHandle);
Gdx.gl20.glVertexAttribPointer(loc, 4, GL20.GL_FLOAT, false, stride, 0);
Defensive patterns

Strategy: type-guard

Validate before calling

private static final Set<Integer> BYTE_BUFFER_TYPES = Set.of(GL20.GL_BYTE, GL20.GL_UNSIGNED_BYTE, GL20.GL_SHORT, GL20.GL_UNSIGNED_SHORT, GL20.GL_FLOAT);
if (buffer instanceof ByteBuffer && !BYTE_BUFFER_TYPES.contains(type)) throw new IllegalArgumentException("ByteBuffer supports BYTE/UBYTE/SHORT/USHORT/FLOAT only");

Type guard

private static boolean isByteBufferAttribTypeOK(java.nio.Buffer b, int type) {
    return !(b instanceof ByteBuffer) || type == GL20.GL_BYTE || type == GL20.GL_UNSIGNED_BYTE
        || type == GL20.GL_SHORT || type == GL20.GL_UNSIGNED_SHORT || type == GL20.GL_FLOAT;
}

Prevention

When it happens

Trigger: Calling Gdx.gl20.glVertexAttribPointer(indx, size, GL_UNSIGNED_INT|GL_FIXED|..., normalized, stride, (ByteBuffer)buffer). Note: int attribute data cannot be passed via ByteBuffer here; and GL_FIXED is GLES-only.

Common situations: Porting Android meshes that use GL_FIXED (GLES1-era) or unsigned-int attributes; hand-written vertex layouts where the type constant was mistyped or copied from an index-buffer call.

Related errors


AI-assisted analysis of libgdx/libgdx@97f4086187 (2026-08-14). Data as JSON: /api/errors/e4a061778559ca75. Report an issue: GitHub.