I have a framebuffer called dirty_fbo with a texture backing called DIRTY_FBO_TEXTURE. I am just trying to readPixels from it and write them back. This is only to figure out whether it works correctly. I intend to later use the pixels read to implement an undo redo etc. elsewhere in my code. My code is as below:

Code :
...
    glBindFramebuffer(GL_FRAMEBUFFER, dirty_fbo);
 
    VBounds bounds = [self get_fbo_bounds];
    GLubyte * old_pixel_data = (GLubyte*) malloc(bounds.width * bounds.height * sizeof(GLubyte) * 4);
    GLubyte * new_pixel_data = (GLubyte*) malloc(bounds.width * bounds.height * sizeof(GLubyte) * 4);
    pixel_data = (GLubyte*) malloc(bounds.width * bounds.height * sizeof(GLubyte) * 4);
 
    glReadPixels(bounds.x, bounds.y, bounds.width, bounds.height, GL_RGBA, GL_UNSIGNED_BYTE, old_pixel_data);
 
    [self draw_path];
 
    glReadPixels(bounds.x, bounds.y, bounds.width, bounds.height, GL_RGBA, GL_UNSIGNED_BYTE, new_pixel_data);
 
    glBindTexture(GL_TEXTURE_2D, DIRTY_FBO_TEXTURE);
    glTexSubImage2D(GL_TEXTURE_2D, 0, bounds.x, bounds.y, bounds.width, bounds.height, GL_RGBA, GL_UNSIGNED_BYTE, old_pixel_data);
 
    free(old_pixel_data);
    free(new_pixel_data);
    free(pixel_data);
...
But for some reason I keep getting GL_INVALID_OPERATION for the glTexSubImage2D call. And I have no idea why. Any pointers at all will be helpful.

Note:

It really is the glTexSubImage2D call that is causing the error. I've verified this.

The bounds calculated are correct.

The DIRTY_FBO_TEXTURE does get drawn to correctly with the draw_paths call. I use the DIRTY_FBO_TEXTURE as a texture for a full-screen quad elsewhere in the program and that works correctly too.

The glTexSubImage2D call params use the same respective values as the initial glTexImage2D call made on the texture at the beginning of the application.