hcengineering/platform · error · ApiError

Invalid width or height

Error message

Invalid width or height

What it means

When both `width` and `height` query parameters are supplied, parsePrintOptions parses them with parseInt and throws this 400 ApiError if either value is NaN — i.e. not a valid base-10 integer. The service requires a numeric viewport to hand to the headless browser; non-numeric input is rejected.

Source

Thrown at services/print/pod-print/src/server.ts:166

    throw new ApiError(400, `Invalid print kind: ${kind}`)
  }

  if (orientation !== undefined && !validPageOrientations.includes(orientation as any)) {
    throw new ApiError(400, `Invalid page orientation: ${orientation}`)
  }

  const rawWidth = (query.width ?? '') as string
  const rawHeight = (query.height ?? '') as string

  let viewport: PrintOptions['viewport'] | undefined
  if (rawWidth.length > 0 && rawHeight.length > 0) {
    viewport = {
      width: parseInt(rawWidth, 10),
      height: parseInt(rawHeight, 10)
    }

    if (Number.isNaN(viewport.width) || Number.isNaN(viewport.height)) {
      throw new ApiError(400, 'Invalid width or height')
    }
  } else if (rawWidth.length > 0 || rawHeight.length > 0) {
    throw new ApiError(400, 'Both width and height must be provided')
  }

  return { kind, orientation, viewport }
}

export function createServer (
  storageConfig: StorageConfiguration,
  allowedHostnames: string[]
): { app: Express, close: () => void } {
  const storageAdapter = buildStorageFromConfig(storageConfig)
  const measureCtx = initStatisticsContext('print', {
    factory: () =>
      createOpenTelemetryMetricsContext(
        'print',
        {},

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Send width/height as pure base-10 integer pixel strings, e.g. width=1280&height=720.
  2. Strip units/client-side and validate with /^\d+$/ before sending.
  3. Omit both parameters entirely to use the print pipeline's default viewport.
  4. If you need fractional or unit-based sizes, convert them to integer pixels first.

Example fix

// before
const w = '12cm'
url += `&width=${w}&height=${h}`
// after
const w = Math.round(12 * 37.795) // 454px
if (/^\d+$/.test(String(w)) && /^\d+$/.test(String(h))) {
  url += `&width=${w}&height=${h}`
}
Defensive patterns

Strategy: validation

Validate before calling

function buildViewportQuery (width?: unknown, height?: unknown): URLSearchParams {
  const q = new URLSearchParams()
  const isInt = (v: unknown) => typeof v === 'number' ? Number.isInteger(v) : /^\d+$/.test(String(v ?? '').trim())
  if (width != null || height != null) {
    if (!isInt(width) || !isInt(height)) throw new Error('width and height must be integer pixels')
    q.set('width', String(width))
    q.set('height', String(height))
  }
  return q
}

Type guard

function isViewportPair (w: unknown, h: unknown): w is number {
  return Number.isInteger(w) && Number.isInteger(h) && (w as number) > 0 && (h as number) > 0
}

Try / catch

try {
  const res = await fetch(url)
  if (!res.ok) {
    const body = await res.json()
    if (body.code === 400 && /Invalid width or height/.test(body.message)) {
      // strip units / re-parse to integers and retry once
    }
    throw new Error(body.message)
  }
  return await res.json()
} catch (err) { /* handle */ }

Prevention

When it happens

Trigger: GET /print?link=...&width=1200px&height=800 (parseInt('1200px') is 1200, but parseInt('w1200') is NaN), or width/height containing commas, units at the start, or empty-looking values like `width=%20` that pass the length check but fail parseInt... note `parseInt(' ')` is NaN.

Common situations: Passing CSS-style sizes ('12cm', '800px' with a leading unit), locale-formatted numbers ('1,200'), or a client that serializes undefined as the string 'undefined' or 'null'.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/6eb18b1317fbe7d8. Report an issue: GitHub.