CherryHQ/cherry-studio · error · Error

useImagePreviewTransform requires minZoom <= maxZoom

Error message

useImagePreviewTransform requires minZoom <= maxZoom

What it means

Thrown synchronously by the useImagePreviewTransform React hook during render when the caller passes a minZoom greater than maxZoom. The hook clamps zoom into [minZoom, maxZoom], so an inverted range is meaningless; it fails fast with a clear invariant message rather than producing broken zoom behavior. Defaults are minZoom=1, maxZoom=5, so this only fires when both options are explicitly supplied in the wrong order.

Source

Thrown at packages/ui/src/components/composites/image-preview/use-image-preview-transform.ts:74

  zoom: clamp(toFiniteNumber(transform?.zoom, DEFAULT_TRANSFORM.zoom), minZoom, maxZoom)
})

const transformsEqual = (left: ImagePreviewTransform, right: ImagePreviewTransform) =>
  left.flipX === right.flipX &&
  left.flipY === right.flipY &&
  left.offsetX === right.offsetX &&
  left.offsetY === right.offsetY &&
  left.rotation === right.rotation &&
  left.zoom === right.zoom

export function useImagePreviewTransform({
  initialTransform,
  maxZoom = 5,
  minZoom = 1,
  zoomStep = 0.25
}: ImagePreviewTransformOptions = {}): ImagePreviewTransformControls {
  if (minZoom > maxZoom) {
    throw new Error('useImagePreviewTransform requires minZoom <= maxZoom')
  }

  if (zoomStep <= 0 || !Number.isFinite(zoomStep)) {
    throw new Error('useImagePreviewTransform requires zoomStep > 0')
  }

  const initialValue = React.useMemo(
    () => normalizeTransform(initialTransform, minZoom, maxZoom),
    [initialTransform, maxZoom, minZoom]
  )
  const [transform, setTransform] = React.useState<ImagePreviewTransform>(initialValue)

  const update = React.useCallback(
    (nextUpdate: ImagePreviewTransformUpdate) => {
      setTransform((current) => {
        const patch = typeof nextUpdate === 'function' ? nextUpdate(current) : nextUpdate
        const next = normalizeTransform({ ...current, ...patch }, minZoom, maxZoom)
        return transformsEqual(current, next) ? current : next

View on GitHub (pinned to 726446b54c)

Solutions

  1. Ensure the passed options satisfy minZoom <= maxZoom (or omit both to use the safe defaults minZoom=1, maxZoom=5).
  2. If bounds come from dynamic config, clamp them at the call site before passing: `const [lo, hi] = order(minRaw, maxRaw)`.
  3. If only one bound is configurable, keep the other at a default that cannot invert (e.g. fixed maxZoom=5 with a minZoom in [1,5]).

Example fix

// before
useImagePreviewTransform({ minZoom: 2, maxZoom: 1 })
// after
useImagePreviewTransform({ minZoom: 1, maxZoom: 5 })
Defensive patterns

Strategy: validation

Validate before calling

// Validate options before calling the hook.
function safeZoomOptions(opts: ImagePreviewTransformOptions): ImagePreviewTransformOptions {
  const minZoom = opts.minZoom ?? 1
  const maxZoom = opts.maxZoom ?? 5
  if (minZoom > maxZoom) {
    throw new Error(`Invalid zoom range: minZoom ${minZoom} > maxZoom ${maxZoom}`)
  }
  return opts
}
const controls = useImagePreviewTransform(safeZoomOptions(props))

Type guard

const isValidZoomOptions = (o: ImagePreviewTransformOptions): boolean => {
  const min = o.minZoom ?? 1
  const max = o.maxZoom ?? 5
  return min <= max && Number.isFinite(min) && Number.isFinite(max)
}

Try / catch

// Hooks throw during render, so wrap the consuming component in an ErrorBoundary rather than try/catch at the call site.
<ErrorBoundary fallback={<ImagePreviewFallback />}>
  <ImagePreview minZoom={props.min} maxZoom={props.max} />
</ErrorBoundary>

Prevention

When it happens

Trigger: Calling `useImagePreviewTransform({ minZoom: 2, maxZoom: 1 })`; passing a maxZoom smaller than a non-default minZoom (e.g. minZoom: 3, maxZoom: 2); computing zoom bounds from config that can invert.

Common situations: Swapping the two numeric props; deriving min/max from user settings or responsive breakpoints where max can drop below min; bad defaults in a wrapper component.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/6fe804f0d7e2e00d. Report an issue: GitHub.