libgdx/libgdx · error · GdxRuntimeException
Cannot change attributes while VBO is bound
Error message
Cannot change attributes while VBO is bound
What it means
setBuffer() swaps the underlying ByteBuffer and VertexAttributes of an InstanceBufferObject. Doing this while the buffer is bound to GL state (isBound == true, set by bind() and cleared by unbind()) would desynchronize the CPU-side view from what the shader attribute pointers were set up against, so the method fail-fasts. This mirrors the same guard in VertexBufferObject.
Source
Thrown at backends/gdx-backends-gwt/src/com/badlogic/gdx/backends/gwt/emu/com/badlogic/gdx/graphics/glutils/InstanceBufferObject.java:96
@Deprecated
public FloatBuffer getBuffer () {
isDirty = true;
return buffer;
}
@Override
public FloatBuffer getBuffer (boolean forWriting) {
isDirty |= forWriting;
return buffer;
}
/** Low level method to reset the buffer and attributes to the specified values. Use with care!
*
* @param data
* @param ownsBuffer
* @param value */
protected void setBuffer (Buffer data, boolean ownsBuffer, VertexAttributes value) {
if (isBound) throw new GdxRuntimeException("Cannot change attributes while VBO is bound");
attributes = value;
if (data instanceof ByteBuffer)
byteBuffer = (ByteBuffer)data;
else
throw new GdxRuntimeException("Only ByteBuffer is currently supported");
this.ownsBuffer = ownsBuffer;
final int l = byteBuffer.limit();
byteBuffer.limit(byteBuffer.capacity());
buffer = byteBuffer.asFloatBuffer();
byteBuffer.limit(l);
buffer.limit(l / 4);
}
private void bufferChanged () {
if (isBound) {
Gdx.gl20.glBufferData(GL20.GL_ARRAY_BUFFER, byteBuffer.limit(), null, usage);
Gdx.gl20.glBufferData(GL20.GL_ARRAY_BUFFER, byteBuffer.limit(), byteBuffer, usage);View on GitHub (pinned to 97f4086187)
Solutions
- Always pair bind()/unbind(): call unbind() (or ensure the drawing API you used ends with it) before calling setBuffer().
- Restructure so attribute-layout changes happen at frame boundaries, not during rendering.
- If an exception can interrupt a draw, catch it and unbind() in a finally block so isBound resets.
Example fix
// before instanceBuffer.bind(shader); instanceBuffer.setBuffer(newData, true, newAttributes); // throws: isBound instanceBuffer.unbind(); // after instanceBuffer.unbind(); instanceBuffer.setBuffer(newData, true, newAttributes); instanceBuffer.bind(shader);
Defensive patterns
Strategy: validation
Validate before calling
// Call setBuffer only when unbound; enforce with your own wrapper:
void reconfigure(InstanceBufferObject ibo, ByteBuffer data, VertexAttributes attrs) {
ibo.unbind(); // no-op safe when not bound in newer versions; else track state
ibo.setBuffer(data, true, attrs);
} Prevention
- Pair every bind() with unbind(), especially on exception paths (finally).
- Change buffer layouts at frame boundaries only.
When it happens
Trigger: Calling setBuffer(...) between bind(shader) and unbind(); reconfiguring attributes from inside a render callback while the instance buffer is bound; a reassign method invoked during a batched draw loop before unbind() ran.
Common situations: Hot-swapping instance attributes (e.g. particle systems changing attribute layout) without unbinding first; refactoring a Mesh-style class so that buffer resets happen mid-draw; forgetting unbind() after an exception interrupted a draw sequence, leaving isBound latched true.
Related errors
- Cannot change usage while VBO is bound
- Already prepared
- No buffer allocated!
- not implemented, vertex arrays aren't support in WebGL it se
- glMapBufferRange not supported on WebGL2
AI-assisted analysis of libgdx/libgdx@97f4086187 (2026-08-14).
Data as JSON: /api/errors/a18aca425986df0a.
Report an issue: GitHub.