{"record":{"id":"540b87ce5090859c","repo":"google/ExoPlayer","slug":"width-or-height-is-less-than-0","errorCode":null,"errorMessage":"width or height is less than 0","messagePattern":"width or height is less than 0","errorType":"exception","errorClass":"GlException","httpStatus":null,"severity":"error","filePath":"library/common/src/main/java/com/google/android/exoplayer2/util/GlUtil.java","lineNumber":443,"sourceCode":"   * @param width The width for a texture.\n   * @param height The height for a texture.\n   * @throws GlException If the texture width or height is invalid.\n   */\n  private static void assertValidTextureSize(int width, int height) throws GlException {\n    // TODO(b/201293185): Consider handling adjustments for sizes > GL_MAX_TEXTURE_SIZE\n    //  (ex. downscaling appropriately) in a shader program instead of asserting incorrect\n    //  values.\n    // For valid GL sizes, see:\n    // https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glTexImage2D.xml\n    int[] maxTextureSizeBuffer = new int[1];\n    GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxTextureSizeBuffer, 0);\n    int maxTextureSize = maxTextureSizeBuffer[0];\n    checkState(\n        maxTextureSize > 0,\n        \"Create a OpenGL context first or run the GL methods on an OpenGL thread.\");\n\n    if (width < 0 || height < 0) {\n      throw new GlException(\"width or height is less than 0\");\n    }\n    if (width > maxTextureSize || height > maxTextureSize) {\n      throw new GlException(\n          \"width or height is greater than GL_MAX_TEXTURE_SIZE \" + maxTextureSize);\n    }\n  }\n\n  /** Fills the pixels in the current output render target with (r=0, g=0, b=0, a=0). */\n  public static void clearOutputFrame() throws GlException {\n    GLES20.glClearColor(/* red= */ 0, /* green= */ 0, /* blue= */ 0, /* alpha= */ 0);\n    GLES20.glClearDepthf(1.0f);\n    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);\n    GlUtil.checkGlError();\n  }\n\n  /**\n   * Makes the specified {@code eglSurface} the render target, using a viewport of {@code width} by\n   * {@code height} pixels.","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/library/common/src/main/java/com/google/android/exoplayer2/util/GlUtil.java#L425-L461","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nint w = videoWidth - 2 * cropPx; // can go negative\nint tex = GlUtil.createTexture(GLES20.GL_TEXTURE_2D, w, videoHeight, false);\n// after\nint w = Math.max(0, videoWidth - 2 * cropPx);\ncheckState(w > 0 && videoHeight > 0, \"Invalid size %dx%d\", w, videoHeight);\nint tex = GlUtil.createTexture(GLES20.GL_TEXTURE_2D, w, videoHeight, false);","handlingStrategy":"validation","validationCode":"if (width < 0 || height < 0) {\n  throw new IllegalArgumentException(\"width/height must be >= 0: \" + width + \"x\" + height);\n}","typeGuard":null,"tryCatchPattern":"Not applicable — a negative size is always a caller bug; fix the computation rather than catching.","preventionTips":["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"],"tags":["opengl","gl","validation","texture"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}