Skip to content

fix: handle non-string input in Replace validator gracefully - #540

Open
binggao1230 wants to merge 2 commits into
alecthomas:masterfrom
binggao1230:fix/replace-non-string-typeerror
Open

binggao1230 wants to merge 2 commits into
alecthomas:masterfrom
binggao1230:fix/replace-non-string-typeerror

Conversation

@binggao1230

Copy link
Copy Markdown
Contributor

The Replace validator calls re.Pattern.sub() directly on the input value. When passed a non-string type (int, None, list, etc.), this raises an unhandled TypeError instead of the expected Invalid exception.

This matches the behavior of the Match validator, which already catches TypeError and raises a proper Invalid error with a descriptive message.

Before (crashes):

>>> from voluptuous.validators import Replace
>>> Replace('hello', 'goodbye')(42)
TypeError: expected string or bytes-like object, got 'int'

After:

>>> from voluptuous.validators import Replace
>>> Replace('hello', 'goodbye')(42)
voluptuous.error.MatchInvalid: expected string or buffer

Changes:

  • Replace._call_ now catches TypeError and raises MatchInvalid
  • Added test_replace_non_string_input covering int, None, list, and custom message cases

Replace.__call__ passed non-string values straight to re.Pattern.sub(),
which raises an unhandled TypeError. Wrap it and raise MatchInvalid
(honouring a custom msg), matching how Match reports the same case.
@binggao1230
binggao1230 force-pushed the fix/replace-non-string-typeerror branch from 7ade908 to 4c75e63 Compare July 15, 2026 08:16
@binggao1230

Copy link
Copy Markdown
Contributor Author

Rebased onto master and dropped the unrelated quote-style churn from the diff — it's now just the Replace fix and its test.

@alecthomas

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4c75e63f90

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread voluptuous/validators.py
Comment on lines +474 to +475
except TypeError:
raise MatchInvalid(self.msg or 'expected string or buffer')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid swallowing TypeError from replacement callbacks

When substitution is a callable accepted by re.Pattern.sub, any TypeError raised inside that callback is now misreported as invalid input. In combinators such as Any, the resulting MatchInvalid is caught and another branch may silently accept the value, hiding a real callback defect; limit the conversion to TypeErrors caused by an incompatible input value.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 80d3204: Replace now validates regex input compatibility before running sub(), so TypeError from a callable replacement propagates unchanged. Added coverage for callback failures and valid bytes-like inputs.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants