docusealco/docuseal · error · Submissions::CreateFromSubmitters::BaseError
Invalid submitter params
Error message
Invalid submitter params
What it means
Submissions::CreateFromSubmitters raises BaseError 'Invalid submitter params' (lib/submissions/create_from_submitters.rb:59) when a submitter entry cannot be matched to any party defined by the template. The uuid is resolved by find_submitter_uuid from (in priority) attrs[:uuid], a case-insensitive role name match on attrs[:role], or positional index; if that resolved uuid does not exist in template_submitters, template_submitter stays nil and the error fires.
Source
Thrown at lib/submissions/create_from_submitters.rb:59
uuid = template_submitter['uuid']
else
if submitter_attrs[:roles].present? && submitter_attrs[:roles].size == 1
submitter_attrs[:role] = submitter_attrs[:roles].first
end
uuid = find_submitter_uuid(template_submitters, submitter_attrs, index)
next if uuid.blank?
next if submitter_attrs.slice('email', 'phone', 'name').compact_blank.blank?
submission.template_fields = submission.template.fields if submitter_attrs[:completed].present? &&
submission.template_fields.blank?
template_submitter = template_submitters.find { |e| e['uuid'] == uuid }
end
raise BaseError, 'Invalid submitter params' unless template_submitter
template_submitter = template_submitter.except('optional_invite_by_uuid', 'invite_by_uuid',
'invite_via_field_uuid')
template_submitter['order'] = submitter_attrs['order'] if submitter_attrs['order'].present?
submission.template_submitters << template_submitter
is_order_sent = submitters_order == 'random' ||
(template_submitter['order'] || submitter_attrs[:index] || index).zero?
build_submitter(submission:, attrs: submitter_attrs,
uuid:, is_order_sent:, user:, params:,
preferences: preferences.merge(submission_preferences))
end
maybe_set_dynamic_documents(submission)
maybe_set_template_fields(submission, attrs[:submitters], with_template:, new_fields:)View on GitHub (pinned to 004a22c1c8)
Solutions
- Fetch the template's parties first (template.submitters names/uuids) and send only role (case-insensitive exact), uuid, or in-range index values that match them.
- If you need one signer to cover several roles, send roles: ['First Role', 'Second Role'] on a single entry instead of duplicating entries with made-up roles.
- Remove surplus submitter entries — every entry must map to a template party (entries without email/phone/name are skipped by design at line 51).
- Regenerate any hard-coded uuids after a template is duplicated or edited.
Example fix
# before
Submissions::CreateFromSubmitters.call(
template:, user:, source: 'api', submitters_order: 'preserved',
submissions_attrs: [{ submitters: [{ role: 'Singger', email: 'a@b.c' }] }] # typo
)
# after
Submissions::CreateFromSubmitters.call(
template:, user:, source: 'api', submitters_order: 'preserved',
submissions_attrs: [{ submitters: [{ role: template.submitters.first['name'], email: 'a@b.c' }] }]
) Defensive patterns
Strategy: validation
Validate before calling
# Validate submitters attrs against the template before calling CreateFromSubmitters
def valid_submitter_params?(template, submitters_attrs)
known_uuids = template.submitters.map { |s| s['uuid'] }
known_roles = template.submitters.map { |s| s['name'].downcase }
Array(submitters_attrs).all? do |attrs_entry|
Array(attrs_entry[:submitters]).all? do |s|
next true if s[:uuid].present? && s[:uuid].in?(known_uuids)
next true if s[:role].present? && known_roles.include?(s[:role].to_s.downcase)
next true if s[:uuid].blank? && s[:role].blank? && # index fallback in range
(s[:index] || submitters_attrs.index(attrs_entry)).to_i < known_uuids.size
false
end
end
end Try / catch
begin
Submissions::CreateFromSubmitters.call(template:, user:, submissions_attrs:, source:, submitters_order:)
rescue Submissions::CreateFromSubmitters::BaseError => e
render json: { error: e.message }, status: :unprocessable_entity
end Prevention
- Always fetch roles/uuids from the live template instead of hard-coding them.
- Regenerate stored uuids whenever a template is duplicated or its parties edited.
- Role matching is case-insensitive but exact otherwise — trim stray whitespace.
- Entries lacking email/phone/name are silently skipped; do not rely on that to fix bad roles.
When it happens
Trigger: POST /api/submissions with a submitters entry whose role/uuid matches none of template.submitters (typo'd role name like 'Signer ' vs 'Signer'); an entry with no uuid/role falling back to an index beyond the template's party count; a uuid copied from a different template; the merge path (attrs[:roles]) raising earlier but leaving a nil template_submitter from a previous skipped iteration.
Common situations: Template roles renamed after an integration was coded; templates recreated and old cached uuids reused; clients sending more subitters than roles expecting extras to be ignored; API consumers assuming 1-based or uuid-based ordering that does not match find_submitter_uuid's index fallback.
Related errors
- Defined more signing parties than in template
- Recipient emails should differ
- file param is missing
- Invalid #{type} value
- Invalid value, url, base64 or text < 60 chars is expected: #
AI-assisted analysis of docusealco/docuseal@004a22c1c8 (2026-08-21).
Data as JSON: /api/errors/a33b41496e7a130c.
Report an issue: GitHub.