docusealco/docuseal · warning · Submitters::UnableToSendCode
Too many attempts.
Error message
Too many attempts.
What it means
Submitters.send_shared_link_email_verification_code (lib/submitters.rb:250) re-raises RateLimit::LimitApproached as UnableToSendCode with the 'Too many attempts.' message. The throttle is RateLimit.call("send-otp-code-#{remote_ip}", limit: 2, ttl: 45.seconds, enabled: true) — at most 2 verification-code emails per source IP per 45 seconds, counted in a process-local memory store. It also logs a Rollbar warning when defined.
Source
Thrown at lib/submitters.rb:250
filename = filename.gsub('{submission.completed_at}') do
completed_at = submitter.submission.completed_at ||
submitter.submission.submitters.select(&:completed_at).max_by(&:completed_at).completed_at
I18n.l(completed_at.in_time_zone(submitter.account.timezone), format: :short)
end
"#{filename}.#{blob.filename.extension}"
end
def send_shared_link_email_verification_code(submitter, request:)
RateLimit.call("send-otp-code-#{request.remote_ip}", limit: 2, ttl: 45.seconds, enabled: true)
TemplateMailer.otp_verification_email(submitter.submission.template, email: submitter.email).deliver_later!
rescue RateLimit::LimitApproached
Rollbar.warning("Limit verification code for template: #{submitter.submission.template.id}") if defined?(Rollbar)
raise UnableToSendCode, I18n.t('too_many_attempts')
end
def verify_link_otp!(otp, submitter)
return false if otp.blank?
RateLimit.call("verify-2fa-code-#{Digest::MD5.base64digest(submitter.email)}",
limit: 2, ttl: 45.seconds, enabled: true)
link_2fa_key = [submitter.email.downcase.squish, submitter.submission.template.slug].join(':')
raise InvalidOtp, I18n.t(:invalid_code) unless EmailVerificationCodes.verify(otp, link_2fa_key)
true
end
def build_document_urls(submitter, ttl: FILES_TTL)
filename_format = AccountConfig.find_or_initialize_by(account_id: submitter.account_id,
key: AccountConfig::DOCUMENT_FILENAME_FORMAT_KEY)&.valueView on GitHub (pinned to 004a22c1c8)
Solutions
- Wait 45 seconds since the last successful send, then request again — the counter key expires with the ttl.
- Rescue Submitters::UnableToSendCode at the controller and return 429 with the too_many_attempts message instead of a 500.
- Disable the resend button client-side for 45s after each send.
- Check the inbox/spam before resending — the first code is still valid.
Example fix
# before (controller)
Submitters.send_shared_link_email_verification_code(submitter, request:)
# after
begin
Submitters.send_shared_link_email_verification_code(submitter, request:)
rescue Submitters::UnableToSendCode
render json: { error: I18n.t('too_many_attempts') }, status: :too_many_requests
end Defensive patterns
Strategy: retry
Try / catch
begin
Submitters.send_shared_link_email_verification_code(submitter, request:)
rescue Submitters::UnableToSendCode
render json: { error: I18n.t('too_many_attempts') }, status: :too_many_requests
end Prevention
- Disable the 'send code' button for 45s after each send (matches limit: 2, ttl: 45.seconds).
- Check spam before resending — earlier codes remain valid.
- Remember the limit is per remote IP, so shared NAT/VPN offices share the budget.
- The counter is per-process memory; clustered deployments may allow slightly more attempts.
When it happens
Trigger: A third 'send code' request within 45 seconds from the same IP on a template shared link; retries after a slow mail send; automated tests or monitoring hammering the endpoint; multiple colleagues behind one NAT IP requesting codes in the same window.
Common situations: Shared office/VPN egress IPs; users clicking 'resend code' repeatedly; frontend auto-retry on timeout; per-process MemoryStore meaning clustered deployments sometimes allow more attempts than configured.
Related errors
- RateLimit::LimitApproached
- Invalid submitter params
- Defined more signing parties than in template
- Recipient emails should differ
- file param is missing
AI-assisted analysis of docusealco/docuseal@004a22c1c8 (2026-08-21).
Data as JSON: /api/errors/31f0a6121d51e0a6.
Report an issue: GitHub.