Skip to content

ai: image sizing can exceed maxRatio or produce NaN #59536

Open

Description

@cyzroot-jpg

Description

ImageSizing.fit() can return a size that violates the provider's maxRatio after snapping each edge to multiple. With the gpt-image limits, aspect: "1:3" at resolution: "1.5K" returns 880x2656 (3.018:1) instead of staying within 3:1.

Degenerate shapes also produce NaN: aspect: "0:0" or resolution: "0K" gives { width: NaN, height: NaN }, and ImageSizing.exact() reports success because comparisons with NaN are false. OpenAI and Meta then build sizes such as NaNxNaN.

Reproduction

const GPT_IMAGE_2 = { multiple: 16, maxEdge: 3840, minPixels: 655360, maxPixels: 8294400, maxRatio: 3 }

ImageSizing.fit({ aspect: "1:3", resolution: "1.5K" }, GPT_IMAGE_2) // 880x2656
ImageSizing.fit({ aspect: "0:0" }, { multiple: 16 }) // NaNxNaN

OpenCode version

dev (2.1.4)

Operating System

Windows 11

Terminal

N/A

Activity

  1. opencode-agent commented on Oct 27, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report. I reproduced both problems on the latest dev (6aedf36) by calling the image-sizing code directly:

    • ImageSizing.fit({ aspect: "1:3", resolution: "1.5K" }) with the gpt-image limits (maxRatio: 3) returns 880x2656, which is 3.018:1 and over the limit.
    • fit with aspect 1:0 or 0:1 (and { multiple: 16 }) returns { width: NaN, height: NaN }, and ImageSizing.exact(...) still succeeds for those aspects.

    The script below reproduces it. Run it from packages/ai in a checkout. The open PR #59535 looks like it addresses this.

    Reproduction script (repro.ts)
    // Run from /workspace/repo/packages/ai: bun /workspace/repro/repro.ts  (REPO env overrides checkout path)
    import { Effect } from "effect"
    const repo = process.env.REPO ?? "/workspace/repo"
    const { ImageSizing } = await import(`${repo}/packages/ai/src/protocols/utils/image-sizing.ts`)
    
    const GPT_IMAGE_2 = { multiple: 16, maxEdge: 3840, minPixels: 655_360, maxPixels: 8_294_400, maxRatio: 3 }
    
    const s = ImageSizing.fit({ aspect: "1:3", resolution: "1.5K" }, GPT_IMAGE_2)
    const ratio = Math.max(s.width, s.height) / Math.min(s.width, s.height)
    console.log("fit 1:3 @1.5K (maxRatio 3):", s, "ratio", ratio.toFixed(4), ratio > 3 ? "EXCEEDS maxRatio" : "ok")
    
    for (const aspect of ["1:0", "0:1"]) {
      console.log(`fit ${aspect} (multiple 16):`, ImageSizing.fit({ aspect }, { multiple: 16 }))
      const route = { name: "test", unsupported: (field: string, msg: string) => new Error(`${field}: ${msg}`) } as any
      const r = await Effect.runPromise(Effect.result(ImageSizing.exact(route, { aspect }, { multiple: 16 })))
      console.log(`exact ${aspect}:`, JSON.stringify(r))
    }

    Run it: bun repro.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions