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

Formula infinite loop

Error message

Formula infinite loop

What it means

Raised by Submitters::SubmitValues.normalize_formula. Formula fields can reference other fields via {{uuid}} placeholders; when a referenced field itself has a preferences.formula, its formula is expanded recursively. A depth counter guards the expansion: recursion deeper than 10 levels means the formula graph is cyclic (or chained beyond 10 formula fields), so the calculation is aborted with 'Formula infinite loop'.

Source

Thrown at lib/submitters/submit_values.rb:239

          end

        values = submission_values.merge(acc.compact_blank)

        acc[field['uuid']] =
          if field['type'] == 'text'
            eval_text_formula_value(formula, values, submitter.submission)
          else
            normalized_formula = normalize_formula(formula, submitter.submission, submission_values:)

            calculate_formula_value(normalized_formula, values)
          end
      end

      computed_values.compact_blank
    end

    def normalize_formula(formula, submission, depth: 0, submission_values: nil)
      raise ValidationError, 'Formula infinite loop' if depth > 10

      formula.gsub(/{{(.*?)}}/) do |match|
        uuid = Regexp.last_match(1)

        if (nested_formula = submission.fields_uuid_index.dig(uuid, 'preferences', 'formula').presence)
          if check_field_conditions(submission_values, submission.fields_uuid_index[uuid], submission.fields_uuid_index)
            "(#{normalize_formula(nested_formula, submission, depth: depth + 1, submission_values:)})"
          else
            '0'
          end
        else
          match
        end
      end
    end

    def calculate_formula_value(_formula, _values)
      0

View on GitHub (pinned to 004a22c1c8)

Solutions

  1. Open the template and remove the circular reference: a formula must not directly or indirectly reference its own field
  2. Flatten deep chains — reference plain number fields instead of stacking formula-on-formula more than 10 levels
  3. Audit every field's preferences.formula for {{uuid}} tokens that resolve to fields which themselves carry a formula
  4. If a two-way calculation is needed, split it into independent fields that read the same source fields

Example fix

# before (template field preferences)
# field A (formula): "{{B}} * 2"
# field B (formula): "{{A}} + 1"   -> cycle: A -> B -> A
# after
# field A (formula): "{{qty}} * {{price}}"
# field B (formula): "{{qty}} * {{price}} + {{tax}}"   (only non-formula references)
Defensive patterns

Strategy: validation

Validate before calling

formulas = submission.template_fields.to_h { |f| [f['uuid'], f.dig('preferences', 'formula').to_s] }
refs = formulas.transform_values { |s| s.scan(/\{\{(\w+)\}\}/).flatten }
cyclic = formulas.keys.any? do |uuid|
  stack = refs[uuid].dup
  seen = [uuid]
  until stack.empty?
    u = stack.pop
    next false if u == uuid || (seen.include?(u) && stack.empty? && u == uuid)
    break true if u == uuid
    seen << u if formulas.key?(u)
    stack.concat(refs[u]) if formulas.key?(u) && !seen.include?(u)
  end == true
end
# reject the template before any submission if cyclic

Try / catch

begin
  Submitters::SubmitValues.call(submitter, params, request)
rescue Submitters::SubmitValues::ValidationError => e
  if e.message == 'Formula infinite loop'
    Rollbar.warning("Cyclic formulas on submission #{submitter.submission_id}") if defined?(Rollbar)
  end
  raise
end

Prevention

When it happens

Trigger: A template formula field whose {{uuid}} placeholder points to another formula field that (directly or via a chain) points back — e.g. A = '{{B}} * 2' and B = '{{A}} + 1', or A = '{{A}}' — or a chain of more than 10 formula fields. Raised on every submit that computes formula values (build_formula_values).

Common situations: A template author copies a formula into a field that field references; a default_value or formula is edited to self-reference after launch, so all subsequent submissions fail; long formula-on-formula chains legitimately exceed depth 10; multi-submitter templates where merged values create an indirect cycle.

Related errors


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