CherryHQ/cherry-studio · error · Error
useImagePreviewTransform requires zoomStep > 0
Error message
useImagePreviewTransform requires zoomStep > 0
What it means
Thrown by the useImagePreviewTransform hook (in @cherrystudio/ui) during render when the zoomStep option is zero, negative, NaN, or Infinity. zoomStep is the delta added/subtracted on each zoomIn/zoomOut call, so a non-positive or non-finite value would make zoom controls non-functional or produce NaN zoom levels. The guard runs before any state is created, failing fast on invalid configuration.
Source
Thrown at packages/ui/src/components/composites/image-preview/use-image-preview-transform.ts:78
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
})
},
[maxZoom, minZoom]
)View on GitHub (pinned to 726446b54c)
Solutions
- Pass a positive finite zoomStep (the default 0.25 is sane): useImagePreviewTransform({ zoomStep: 0.25 }) or omit the option entirely.
- If zoomStep is dynamic, sanitize it before the call: const safeZoomStep = zoomStep > 0 && Number.isFinite(zoomStep) ? zoomStep : 0.25.
- Check the call site feeding zoomStep — if it comes from user settings/preferences, ensure the schema clamps the minimum above 0.
- Add a unit test asserting the hook accepts its documented range and rejects 0/negative/NaN.
Example fix
// before
useImagePreviewTransform({ zoomStep: 0 }) // throws
// after
useImagePreviewTransform({ zoomStep: 0.25 }) Defensive patterns
Strategy: validation
Validate before calling
// Validate before calling the hook (hook-level guards cannot be conditional)
const safeZoomStep =
typeof zoomStep === 'number' && zoomStep > 0 && Number.isFinite(zoomStep)
? zoomStep
: 0.25 // sane default
useImagePreviewTransform({ zoomStep: safeZoomStep, minZoom, maxZoom }) Type guard
const isValidZoomStep = (v: unknown): v is number => typeof v === 'number' && v > 0 && Number.isFinite(v)
Prevention
- Never derive zoomStep from an unchecked division (1/count) without guarding count > 0.
- Keep zoomStep as a constant or a preferences value clamped to > 0 by its schema.
- Add a unit test asserting the hook rejects 0, negative, NaN, and Infinity.
When it happens
Trigger: Calling useImagePreviewTransform({ zoomStep: 0 }), with a negative value (zoomStep: -0.5), or passing a computed value that evaluated to NaN/Infinity (e.g. zoomStep: someRatio where someRatio is NaN). Also triggered if zoomStep is derived from user input or a config file that was mis-parsed into a string then cast with Number().
Common situations: Passing zoomStep: 0 thinking it disables zoom; deriving zoomStep from a division that can yield NaN (e.g. 1/count when count is 0); reading a numeric setting from preferences that defaults to 0 before the user configures it; serializing/deserializing config where the number became a string and Number() coerced an empty string to 0.
Related errors
- useImagePreviewTransform requires minZoom <= maxZoom
- ${name} must be used inside <TreeView />
- Invalid MCP package upload: file name must be a string
- Private key must be a non-empty string
- Invalid PEM format: missing BEGIN/END markers or key content
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/5a56ca0f020584c7.
Report an issue: GitHub.