mozilla/pdf.js · error · Error
Invalid updateScale options: either `steps` or `scaleFactor`
Error message
Invalid updateScale options: either `steps` or `scaleFactor` must be provided.
What it means
PDFViewer.updateScale() changes the current zoom either by a multiplicative `scaleFactor` or by N discrete `steps` (powered by DEFAULT_SCALE_DELTA). Both parameters default to `null`, so the method refuses to guess and throws when neither is supplied. It is a contract guard: exactly one zoom strategy must be present. Note that `increaseScale`/`decreaseScale` always inject `steps`, so this only fires when `updateScale` is called directly with an empty or stripped options object.
Source
Thrown at web/pdf_viewer.js:2585
* @property {number} [steps]
* @property {Array} [origin] x and y coordinates of the scale
* transformation origin.
* @property {Array<number>} [pan] - Horizontal and vertical gesture deltas.
*/
/**
* Changes the current zoom level by the specified amount.
* @param {ChangeScaleOptions} [options]
*/
updateScale({
drawingDelay,
scaleFactor = null,
steps = null,
origin,
pan = null,
}) {
if (steps === null && scaleFactor === null) {
throw new Error(
"Invalid updateScale options: either `steps` or `scaleFactor` must be provided."
);
}
if (!this.pdfDocument) {
return;
}
let newScale = this._currentScale;
if (scaleFactor > 0 && scaleFactor !== 1) {
newScale = Math.round(newScale * scaleFactor * 100) / 100;
} else if (steps) {
const delta = steps > 0 ? DEFAULT_SCALE_DELTA : 1 / DEFAULT_SCALE_DELTA;
const round = steps > 0 ? Math.ceil : Math.floor;
steps = Math.abs(steps);
do {
newScale = round((newScale * delta).toFixed(2) * 10) / 10;
} while (--steps > 0);
}
newScale = MathClamp(newScale, MIN_SCALE, MAX_SCALE);View on GitHub (pinned to 5903d58d58)
Solutions
- Always pass exactly one of `steps` (integer, negative shrinks) or `scaleFactor` (positive multiplier != 1) when calling updateScale.
- If you only have a target scale, compute it yourself: prefer `pdfViewer.currentScaleValue` / the `#setScale` path, or derive `scaleFactor = targetScale / pdfViewer.currentScale`.
- For incremental zoom buttons, call `increaseScale()` / `decreaseScale()` instead of `updateScale` directly — they inject `steps` for you.
- When forwarding a user/options bag, default it explicitly: `updateScale({ steps: 1, ...opts })` so a missing key cannot leave both null.
Example fix
// before
pdfViewer.updateScale({ origin: [x, y] });
// after
pdfViewer.updateScale({ scaleFactor: 1.1, origin: [x, y] });
// or, for discrete stepping:
pdfViewer.increaseScale({ origin: [x, y] }); Defensive patterns
Strategy: validation
Validate before calling
// Validate before calling updateScale.
function safeUpdateScale(viewer, opts = {}) {
const hasFactor = typeof opts.scaleFactor === 'number' && opts.scaleFactor > 0 && opts.scaleFactor !== 1;
const hasSteps = Number.isInteger(opts.steps);
if (!hasFactor && !hasSteps) {
throw new TypeError('updateScale needs `steps` (integer) or `scaleFactor` (>0, !=1)');
}
viewer.updateScale(opts);
} Type guard
/** @param {unknown} o */
function isChangeScaleOptions(o) {
if (!o || typeof o !== 'object') return false;
const { scaleFactor, steps } = /** @type {any} */ (o);
const factorOk = scaleFactor == null || (typeof scaleFactor === 'number' && scaleFactor > 0);
const stepsOk = steps == null || Number.isInteger(steps);
return factorOk && stepsOk && (scaleFactor != null || steps != null);
} Try / catch
try {
viewer.updateScale(opts);
} catch (e) {
if (/Invalid updateScale options/.test(e.message)) {
// degrade: default to one discrete step instead of crashing the UI
viewer.increaseScale({ origin: opts.origin });
} else {
throw e;
}
} Prevention
- Prefer increaseScale()/decreaseScale() wrappers — they always set steps.
- When forwarding a user options bag, merge a default: `{ steps: 1, ...userOpts }`.
- Treat scaleFactor of 0, negative, or 1 as 'no zoom intent' and convert to steps.
When it happens
Trigger: Calling `pdfViewer.updateScale({})`, `pdfViewer.updateScale({ origin, pan })` (only transform metadata, no zoom delta), or spreading a user-supplied options bag whose `steps`/`scaleFactor` keys are absent/undefined. Also triggered by code that destructures options and forwards a filtered subset that accidentally drops both keys.
Common situations: A custom toolbar or pinch-zoom handler builds a ChangeScaleOptions object dynamically and forwards it without guaranteeing a zoom field; refactoring that removes the `scaleFactor` branch but forgets to set `steps`; passing `scaleFactor: 0` or `scaleFactor: 1` is NOT the trigger (those fall through to the `steps` branch) — the trigger is strictly both being null.
Related errors
- Invalid pageIndex request.
- Invalid numeric scale.
- The AnnotationEditor is not enabled.
- BinaryCMapReader.process: Invalid dataSize.
- Page count in top-level pages dictionary is not an integer.
AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13).
Data as JSON: /api/errors/5cfaf07b765b5a31.
Report an issue: GitHub.