hcengineering/platform · error · ApiError

Invalid page orientation: ${orientation}

Error message

Invalid page orientation: ${orientation}

What it means

The print service validates the optional `orientation` query parameter against a fixed list of supported values (validPageOrientations). If the client passes an orientation string that is not one of those values, parsePrintOptions throws this 400 ApiError before any printing is attempted. It exists to fail fast on malformed print options rather than pass garbage into the headless print pipeline.

Source

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

    next(err)
  }
}

const wrapRequest = (fn: AsyncRequestHandler) => (req: Request, res: Response, next: NextFunction) => {
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
  handleRequest(fn, req, res, next)
}

function parsePrintOptions (query: Request['query']): PrintOptions {
  const kind = query.kind as PrintOptions['kind']
  const orientation = query.orientation as PrintOptions['orientation']

  if (kind !== undefined && !validKinds.includes(kind as any)) {
    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')
  }

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Check the supported values in services/print/pod-print/src/print.ts (validPageOrientations) and send one of them exactly.
  2. Send orientation omitted entirely if you don't need a non-default orientation (the check only runs when the parameter is present).
  3. Normalize the value client-side: lowercase and trim before building the query string.
  4. If the server's allowed list needs new values, extend validPageOrientations in print.ts.

Example fix

// before
fetch(`/print?link=${link}&orientation=LandScape`)
// after
fetch(`/print?link=${link}&orientation=${'landscape'.trim().toLowerCase()}`)
Defensive patterns

Strategy: validation

Validate before calling

const VALID_ORIENTATIONS = ['portrait', 'landscape'] // mirror validPageOrientations from ./print
const q = new URLSearchParams()
if (orientation != null) {
  const normalized = String(orientation).trim().toLowerCase()
  if (!VALID_ORIENTATIONS.includes(normalized)) {
    throw new Error(`orientation must be one of: ${VALID_ORIENTATIONS.join(', ')}`)
  }
  q.set('orientation', normalized)
}

Type guard

function isValidOrientation (v: unknown): v is 'portrait' | 'landscape' {
  return typeof v === 'string' && ['portrait', 'landscape'].includes(v)
}

Try / catch

try {
  const res = await fetch(url)
  if (!res.ok) {
    const body = await res.json()
    if (body.code === 400 && /orientation/i.test(body.message)) {
      // correct orientation param and retry
    }
    throw new Error(body.message)
  }
  return await res.json()
} catch (err) { /* handle */ }

Prevention

When it happens

Trigger: Calling GET /print or GET /print/:objectClass/:objectId with `?orientation=` set to anything other than an entry in validPageOrientations (e.g. 'landscape ' with trailing space, 'LandScape' wrong case, or a misspelled value).

Common situations: Clients hardcoding orientation strings from another API's vocabulary; template code building URLs that URL-encodes or appends whitespace; case-sensitivity surprises since the comparison is exact-match against lowercase values.

Related errors


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