google/ExoPlayer · error · GlException
width or height is less than 0
Error message
width or height is less than 0
What it means
Thrown by GlUtil.assertValidTextureSize(width, height) when width or height is negative. Before this check the method also verifies a GL context exists (GL_MAX_TEXTURE_SIZE must be > 0), so reaching this specific message means the GL state was fine but the caller supplied a dimension less than 0. Texture dimensions are fundamentally unsigned in GLES, so a negative size indicates an upstream computation or uninitialized-value bug rather than a device limitation.
Source
Thrown at library/common/src/main/java/com/google/android/exoplayer2/util/GlUtil.java:443
* @param width The width for a texture.
* @param height The height for a texture.
* @throws GlException If the texture width or height is invalid.
*/
private static void assertValidTextureSize(int width, int height) throws GlException {
// TODO(b/201293185): Consider handling adjustments for sizes > GL_MAX_TEXTURE_SIZE
// (ex. downscaling appropriately) in a shader program instead of asserting incorrect
// values.
// For valid GL sizes, see:
// https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glTexImage2D.xml
int[] maxTextureSizeBuffer = new int[1];
GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxTextureSizeBuffer, 0);
int maxTextureSize = maxTextureSizeBuffer[0];
checkState(
maxTextureSize > 0,
"Create a OpenGL context first or run the GL methods on an OpenGL thread.");
if (width < 0 || height < 0) {
throw new GlException("width or height is less than 0");
}
if (width > maxTextureSize || height > maxTextureSize) {
throw new GlException(
"width or height is greater than GL_MAX_TEXTURE_SIZE " + maxTextureSize);
}
}
/** Fills the pixels in the current output render target with (r=0, g=0, b=0, a=0). */
public static void clearOutputFrame() throws GlException {
GLES20.glClearColor(/* red= */ 0, /* green= */ 0, /* blue= */ 0, /* alpha= */ 0);
GLES20.glClearDepthf(1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GlUtil.checkGlError();
}
/**
* Makes the specified {@code eglSurface} the render target, using a viewport of {@code width} by
* {@code height} pixels.View on GitHub (pinned to dd430f7053)
Solutions
- Trace where the negative dimension originates: log width/height at every transform step (parse -> scale -> rotate -> texture) and clamp sentinels (C.LENGTH_UNSET == -1) before use
- Guard with a precondition before calling GL helpers: if (w <= 0 || h <= 0) throw/fallback with a descriptive upstream error
- If the value is legitimately unknown yet, defer texture creation until the format is resolved (e.g. onOutputFormatChanged / first frame arrived)
- Fix the arithmetic: recompute sizes after applying crop/scaling in the correct order and use long or Math.max(0, ...) for intermediates
Example fix
// before int w = videoWidth - 2 * cropPx; // can go negative int tex = GlUtil.createTexture(GLES20.GL_TEXTURE_2D, w, videoHeight, false); // after int w = Math.max(0, videoWidth - 2 * cropPx); checkState(w > 0 && videoHeight > 0, "Invalid size %dx%d", w, videoHeight); int tex = GlUtil.createTexture(GLES20.GL_TEXTURE_2D, w, videoHeight, false);
Defensive patterns
Strategy: validation
Validate before calling
if (width < 0 || height < 0) {
throw new IllegalArgumentException("width/height must be >= 0: " + width + "x" + height);
} Try / catch
Not applicable — a negative size is always a caller bug; fix the computation rather than catching.
Prevention
- Treat -1 sentinels (C.LENGTH_UNSET, C.INDEX_UNSET, unset VideoSize) as 'unknown' and defer GL allocation
- Compute scaled sizes with Math.max(0, ...) guards
- Unit-test dimension math for edge aspect ratios and crops
When it happens
Trigger: Passing a negative width/height to GlUtil.createTexture, createFbo, or any helper that funnels into assertValidTextureSize. Common sources: video width/height parsed as -1 (C.LENGTH_UNSET / C.INDEX_UNSET leaking through), rotating/swapping dimensions of an uninitialized rectangle, or arithmetic like width - padding going negative after crop/margins are misapplied.
Common situations: Effects/Transformer pipelines where input ColorInfo or VideoSize was not yet resolved (still -1 sentinel) when the texture is created; computing scaled sizes with int overflow or wrong order (margin subtracted twice); applying rotation math that flips a dimension sign for odd aspect ratios.
Related errors
- No call to setSamplerTexId() before bind.
- Unexpected uniform type: {type}
- glError: {gluErrorString(error)}
- Unexpected color filter ${colorFilterSelection}
- The item must specify its mimeType
AI-assisted analysis of google/ExoPlayer@dd430f7053 (2026-08-14).
Data as JSON: /api/errors/540b87ce5090859c.
Report an issue: GitHub.