hcengineering/platform · error · ApiError

Invalid includeAttachments. Must be boolean

Error message

Invalid includeAttachments. Must be boolean

What it means

The pod-export server validates the optional `includeAttachments` parameter must be a boolean when supplied. This HTTP 400 error is thrown when the value is present but not of boolean type, protecting the export handler from coercible-but-wrong types.

Source

Thrown at services/export/pod-export/src/server.ts:504

          includeChildren?: boolean
        } = req.body

        // Validate required parameters
        if (targetWorkspace == null || typeof targetWorkspace !== 'string') {
          measureCtx.warn(`Invalid targetWorkspace parameter: ${String(targetWorkspace)}`)
          throw new ApiError(400, 'Missing or invalid required parameter: targetWorkspace')
        }
        if (_class == null || typeof _class !== 'string') {
          measureCtx.warn(`Invalid _class parameter: ${String(_class)}`)
          throw new ApiError(400, 'Missing or invalid required parameter: _class')
        }
        if (conflictStrategy !== undefined && conflictStrategy !== 'skip' && conflictStrategy !== 'duplicate') {
          measureCtx.warn(`Invalid conflictStrategy: ${String(conflictStrategy)}`)
          throw new ApiError(400, 'Invalid conflictStrategy. Must be "skip" or "duplicate"')
        }
        if (includeAttachments !== undefined && typeof includeAttachments !== 'boolean') {
          measureCtx.warn(`Invalid includeAttachments: ${String(includeAttachments)}`)
          throw new ApiError(400, 'Invalid includeAttachments. Must be boolean')
        }

        decodedToken = decodeToken(token)
        if (decodedToken.extra?.readonly !== undefined) {
          throw new ApiError(403, 'Forbidden: read-only token')
        }

        // Get target workspace info
        const accountClient = getClient(envConfig.AccountsUrl, token)
        const targetWsLoginInfo = await accountClient.getLoginWithWorkspaceInfo()

        const targetWsInfo = targetWsLoginInfo.workspaces[targetWorkspace]
        if (targetWsInfo === undefined) {
          measureCtx.warn(`Target workspace not found or not accessible: ${targetWorkspace}`)
          throw new ApiError(404, 'Target workspace not found or not accessible')
        }

        // Verify user has write access to target workspace

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Send a real boolean: includeAttachments=true or includeAttachments=false (unquoted, boolean JSON type).
  2. Coerce before sending in the client: value === 'true' ? true : value === 'false' ? false : undefined.
  3. Omit the parameter if the default behavior is fine.

Example fix

// before
params.includeAttachments = 'true'
// after
params.includeAttachments = String(raw).toLowerCase() === 'true' ? true : undefined
Defensive patterns

Strategy: validation

Validate before calling

if (includeAttachments !== undefined && typeof includeAttachments !== 'boolean') {
  throw new Error('includeAttachments must be a boolean when provided')
}

Type guard

function isBooleanOrUndefined(v: unknown): v is boolean | undefined {
  return v === undefined || typeof v === 'boolean'
}

Try / catch

try {
  await exportPod(params)
} catch (err) {
  if (err instanceof ApiError && err.status === 400 && /includeAttachments/.test(err.message)) {
    console.error('includeAttachments must be a real boolean, not a string/number')
  } else throw err
}

Prevention

When it happens

Trigger: Passing includeAttachments='true' (string), 1 (number), 'yes', or any non-boolean value to the export endpoint.

Common situations: Query-string parameters arrive as strings, so callers who take user input straight from a URL or form and forward it verbatim hit this; scripts quoting booleans; JSON bodies using 0/1 instead of true/false.

Related errors


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