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 : nextView on GitHub (pinned to 726446b54c)
Solutions
- Ensure the passed options satisfy minZoom <= maxZoom (or omit both to use the safe defaults minZoom=1, maxZoom=5).
- If bounds come from dynamic config, clamp them at the call site before passing: `const [lo, hi] = order(minRaw, maxRaw)`.
- 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
- Omit minZoom/maxZoom to accept the safe defaults (1 and 5).
- When bounds come from config, normalize them at the call site so min is always <= max before passing.
- Add a unit test asserting useImagePreviewTransform throws for inverted ranges and accepts valid ones.
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
- useImagePreviewTransform requires zoomStep > 0
- Private key must be a non-empty string
- Invalid PEM format: missing BEGIN/END markers or key content
- Private key content is empty after cleaning
- Private key contains invalid characters (not valid Base64)
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/6fe804f0d7e2e00d.
Report an issue: GitHub.