docusealco/docuseal · error · Submitters::SubmitValues::ValidationError

Invalid field

Error message

Invalid field

What it means

Raised by Submitters::SubmitValues.maybe_set_signature_reason! when a submit request carries a with_reason parameter (declining a signature with a reason) and the template field found under that reason UUID already exists, but its preferences.signature_field_uuid does not point at the signature field whose UUID is the other key in the submitted values hash. The service auto-creates and links a reason field only when the reason UUID is brand new; an existing field must already belong to that exact signature field.

Source

Thrown at lib/submitters/submit_values.rb:122

    end

    def maybe_set_signature_reason!(values, submitter, params)
      return if params[:with_reason].blank?

      reason_field_uuid = params[:with_reason]
      signature_field_uuid = values.except(reason_field_uuid).keys.first

      signature_field = submitter.submission.template_fields.find do |e|
        e['uuid'] == signature_field_uuid && e['submitter_uuid'] == submitter.uuid
      end

      reason_field = submitter.submission.template_fields.find do |e|
        e['uuid'] == reason_field_uuid
      end

      if reason_field
        if reason_field.dig('preferences', 'signature_field_uuid') != signature_field['uuid']
          raise ValidationError, 'Invalid field'
        end
      else
        reason_field = { 'type' => 'text',
                         'uuid' => reason_field_uuid,
                         'name' => I18n.t(:reason),
                         'readonly' => true,
                         'preferences' => { 'signature_field_uuid' => signature_field['uuid'] },
                         'submitter_uuid' => submitter.uuid }

        submitter.submission.template_fields.insert(submitter.submission.template_fields.index(signature_field) + 1,
                                                    reason_field)
      end

      signature_field['preferences'] ||= {}
      signature_field['preferences']['reason_field_uuid'] = reason_field_uuid

      submitter.submission.save!

View on GitHub (pinned to 004a22c1c8)

Solutions

  1. Send a freshly generated UUID as with_reason for each declined signature so the service creates and links the reason field itself
  2. If reusing an existing reason field, verify field['preferences']['signature_field_uuid'] equals the signature field UUID you are submitting before sending
  3. Fix the template so the reason field's preferences.signature_field_uuid references the intended signature field
  4. Omit with_reason entirely if no decline reason needs to be recorded

Example fix

# before
Submitters::SubmitValues.call(submitter, { values: { 'sig_a_uuid' => 'Declined' }, with_reason: 'reason_uuid_created_for_sig_b' }, request)
# after — fresh uuid lets the service create + link the reason field to sig_a
Submitters::SubmitValues.call(submitter, { values: { 'sig_a_uuid' => 'Declined' }, with_reason: SecureRandom.uuid }, request)
Defensive patterns

Strategy: validation

Validate before calling

sig_uuid = values.except(params[:with_reason]).keys.first
existing = submitter.submission.template_fields.find { |f| f['uuid'] == params[:with_reason] }
if existing && existing.dig('preferences', 'signature_field_uuid') != sig_uuid
  params[:with_reason] = SecureRandom.uuid # let the service create a fresh linked reason field
end

Try / catch

begin
  Submitters::SubmitValues.update_submitter!(submitter, params, request)
rescue Submitters::SubmitValues::ValidationError => e
  # e.message == 'Invalid field': with_reason uuid is linked to another signature field
  render json: { error: e.message }, status: :unprocessable_entity
end

Prevention

When it happens

Trigger: Submitting values containing exactly one signature-field UUID plus params[:with_reason] = '<uuid>', where '<uuid>' matches an existing template_fields entry (a reason field created for a different signature, or any unrelated field) whose preferences.signature_field_uuid differs from the signature field UUID being submitted.

Common situations: A front-end reuses one hard-coded reason UUID for several signature fields; a template was copied so a reason field linked to another signature survives; a client passes an existing field's UUID instead of generating a fresh one; retrying a decline against a different signature field with the same reason UUID.

Related errors


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