#2391·Guardrails

bug: Presidio Sensitive Data Detection with custom recognizers cannot be called twice

Author: RobGeadaCreated Sep 17, 2026Updated Sep 17, 2026
Labelsbugstatus: needs triage

Did you check docs and existing issues?

  • I have read all the NeMo-Guardrails docs
  • I have updated the package to the latest version before submitting this issue
  • (optional) I have used the develop branch
  • I have searched the existing issues of NeMo-Guardrails

Python version (python --version)

Python 3.12.7

Operating system/version

Irrelevant

NeMo-Guardrails version (if you must use a specific version and not the latest

latest develop

Describe the bug

When using a custom Presidio recognizer, e.g.:

rails:
  input:
    flows:
      - mask sensitive data on input

  config:
    sensitive_data_detection:
      recognizers:
        - name: "Canadian Passport"
          supported_entity: "CA_PASSPORT"
          patterns:
            - name: "canada_passport_regex"
              regex: "(\\b[A-Z]{2}[0-9]{6}\\b)"
              score: 1

      # curated for the AI4Privacy PII Types
      input:
        entities:
          - CA_PASSPORT

You can only call this config once. On the second call, Presidio will throw a type error:

`ERROR:nemoguardrails.actions.action_dispatcher:presidio_analyzer.pattern.Pattern() argument after ** must be a mapping, not Pattern
  Traceback (most recent call last):
    File "/.../NeMo-Guardrails/nemoguardrails/actions/action_dispatcher.py", line 357, in execute_action
      result = await result
               ^^^^^^^^^^^^
    File "/.../NeMo-Guardrails/nemoguardrails/library/sensitive_data_detection/actions.py", line 200, in
  mask_sensitive_data
      ad_hoc_recognizers=_get_ad_hoc_recognizers(sdd_config),
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/.../NeMo-Guardrails/nemoguardrails/library/sensitive_data_detection/actions.py", line 97, in
  _get_ad_hoc_recognizers
      ad_hoc_recognizers.append(PatternRecognizer.from_dict(recognizer))
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File
  "/.../nemo-guardrails-local-dev/.venv/lib/python3.12/site-packages/presidio_analyzer/pattern_recognizer.py", line
  271, in from_dict
      patterns_list = [Pattern.from_dict(pat) for pat in patterns]
                       ^^^^^^^^^^^^^^^^^^^^^^
    File "/.../nemo-guardrails-local-dev/.venv/lib/python3.12/site-packages/presidio_analyzer/pattern.py", line 38,
  in from_dict
      return cls(**pattern_dict)
             ^^^^^^^^^^^^^^^^^^^
  TypeError: presidio_analyzer.pattern.Pattern() argument after ** must be a mapping, not Pattern`

This is because the Presidio PatternRecognizer.from_dict(recognizer) function modifies the passed recognizer object, and renders it incompatible with a second call to the function. To remedy this, pass a copy of the recognizer dict to the function. Will open a PR shortly.

Steps To Reproduce

  1. Deploy a config with a custom Presidio pattern
  2. Call NeMo guardrails twice

Expected Behavior

The rail continues to work each time

Actual Behavior

The second request fails