docusealco/docuseal · error · Params::BaseValidator::InvalidParameterError

#{message}

Error message

#{message}

What it means

Params::BaseValidator is the base class for structured API parameter validation; raise_error appends the current JSON path ('in `path`') and raises InvalidParameterError unless the validator runs in dry_run mode. The literal message is interpolated - each concrete validator supplies texts like 'x or y is required' from the required/type helpers. These errors back the API's invalid-parameter (422-style) responses.

Source

Thrown at lib/params/base_validator.rb:40

    attr_reader :params, :dry_run

    alias dry_run? dry_run

    def initialize(params, dry_run: false)
      @params = params
      @dry_run = dry_run
      @current_path = ''
    end

    def call
      raise NotImplementedError
    end

    def raise_error(message)
      message += " in `#{@current_path}`." if @current_path.present?

      raise InvalidParameterError, message unless dry_run?
    end

    def required(params, keys, message: nil)
      keys = Array.wrap(keys)

      return if keys.any? { |key| params&.dig(key).present? }

      raise_error(message || "#{keys.join(' or ')} is required")
    end

    def type(params, key, type, message: nil)
      return if params.blank?
      return if params[key].blank?

      return if params[key].is_a?(type) || (type == Hash && params[key].is_a?(ActionController::Parameters))

      type = 'Object' if type == Hash

View on GitHub (pinned to 004a22c1c8)

Solutions

  1. Read the message literally: it names the exact parameter and the JSON path where validation failed.
  2. Diff your payload against the endpoint's documented schema and fix nesting per the path suffix.
  3. Use the validator's dry_run mode in tests to collect all errors at once instead of one per request.
  4. If the message seems wrong, check the endpoint's validator class for the exact required/type rules.

Example fix

# before
required(params, %i[template_id])

# after -- clearer message for API consumers
required(params, %i[template_id], message: 'template_id or template_blob is required')
Defensive patterns

Strategy: validation

Validate before calling

// client-side: check required keys before sending
const REQUIRED = ['template_id']
const missing = REQUIRED.filter((k) => body[k] == null)
if (missing.length) throw new Error(`Missing: ${missing.join(', ')}`)

Type guard

const hasRequiredKeys = (b) =>
  typeof b === 'object' && b !== null && REQUIRED.every((k) => b[k] != null && b[k] !== '')

Try / catch

try {
  await api.post('/api/submissions', body)
} catch (e) {
  if (e.status === 422) mapFieldErrors(e.body) // message names the param + path
  else throw e
}

Prevention

When it happens

Trigger: Calling a validated API endpoint with missing required keys, wrong types, or values failing nested checks - for example a create call missing every key passed to required(), or a string sent where the type check expects an array.

Common situations: API consumers omitting optional-looking-but-required fields; wrong request nesting (the path suffix in the message shows where); schema changes between versions; integrations written against outdated docs.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of docusealco/docuseal@004a22c1c8 (2026-08-21). Data as JSON: /api/errors/6dbb0895b9be2086. Report an issue: GitHub.