{"record":{"id":"6eb18b1317fbe7d8","repo":"hcengineering/platform","slug":"invalid-width-or-height","errorCode":null,"errorMessage":"Invalid width or height","messagePattern":"Invalid width or height","errorType":"validation","errorClass":"ApiError","httpStatus":400,"severity":"error","filePath":"services/print/pod-print/src/server.ts","lineNumber":166,"sourceCode":"    throw new ApiError(400, `Invalid print kind: ${kind}`)\n  }\n\n  if (orientation !== undefined && !validPageOrientations.includes(orientation as any)) {\n    throw new ApiError(400, `Invalid page orientation: ${orientation}`)\n  }\n\n  const rawWidth = (query.width ?? '') as string\n  const rawHeight = (query.height ?? '') as string\n\n  let viewport: PrintOptions['viewport'] | undefined\n  if (rawWidth.length > 0 && rawHeight.length > 0) {\n    viewport = {\n      width: parseInt(rawWidth, 10),\n      height: parseInt(rawHeight, 10)\n    }\n\n    if (Number.isNaN(viewport.width) || Number.isNaN(viewport.height)) {\n      throw new ApiError(400, 'Invalid width or height')\n    }\n  } else if (rawWidth.length > 0 || rawHeight.length > 0) {\n    throw new ApiError(400, 'Both width and height must be provided')\n  }\n\n  return { kind, orientation, viewport }\n}\n\nexport function createServer (\n  storageConfig: StorageConfiguration,\n  allowedHostnames: string[]\n): { app: Express, close: () => void } {\n  const storageAdapter = buildStorageFromConfig(storageConfig)\n  const measureCtx = initStatisticsContext('print', {\n    factory: () =>\n      createOpenTelemetryMetricsContext(\n        'print',\n        {},","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/print/pod-print/src/server.ts#L148-L184","documentation":"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.","triggerScenarios":"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.","commonSituations":"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'.","solutions":["Send width/height as pure base-10 integer pixel strings, e.g. width=1280&height=720.","Strip units/client-side and validate with /^\\d+$/ before sending.","Omit both parameters entirely to use the print pipeline's default viewport.","If you need fractional or unit-based sizes, convert them to integer pixels first."],"exampleFix":"// before\nconst w = '12cm'\nurl += `&width=${w}&height=${h}`\n// after\nconst w = Math.round(12 * 37.795) // 454px\nif (/^\\d+$/.test(String(w)) && /^\\d+$/.test(String(h))) {\n  url += `&width=${w}&height=${h}`\n}","handlingStrategy":"validation","validationCode":"function buildViewportQuery (width?: unknown, height?: unknown): URLSearchParams {\n  const q = new URLSearchParams()\n  const isInt = (v: unknown) => typeof v === 'number' ? Number.isInteger(v) : /^\\d+$/.test(String(v ?? '').trim())\n  if (width != null || height != null) {\n    if (!isInt(width) || !isInt(height)) throw new Error('width and height must be integer pixels')\n    q.set('width', String(width))\n    q.set('height', String(height))\n  }\n  return q\n}","typeGuard":"function isViewportPair (w: unknown, h: unknown): w is number {\n  return Number.isInteger(w) && Number.isInteger(h) && (w as number) > 0 && (h as number) > 0\n}","tryCatchPattern":"try {\n  const res = await fetch(url)\n  if (!res.ok) {\n    const body = await res.json()\n    if (body.code === 400 && /Invalid width or height/.test(body.message)) {\n      // strip units / re-parse to integers and retry once\n    }\n    throw new Error(body.message)\n  }\n  return await res.json()\n} catch (err) { /* handle */ }","preventionTips":["Send width/height as plain integer pixel strings only.","Strip CSS units (px, cm) client-side before sending.","Validate with /^\\d+$/ before appending to the query.","Never serialize undefined/null into the width or height params."],"tags":["validation","http-400","query-params","viewport"],"backgroundTag":"invalid-parameter-value","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}