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

  1. 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
  2. Guard with a precondition before calling GL helpers: if (w <= 0 || h <= 0) throw/fallback with a descriptive upstream error
  3. If the value is legitimately unknown yet, defer texture creation until the format is resolved (e.g. onOutputFormatChanged / first frame arrived)
  4. 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

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


AI-assisted analysis of google/ExoPlayer@dd430f7053 (2026-08-14). Data as JSON: /api/errors/540b87ce5090859c. Report an issue: GitHub.