The spec subagents turn every test that fails on the current code into a suspected violation. Each one was reviewed by reading the code and searching the upstream issues.
emailnew2 test entries
Quoted-string local part with space is rejected
Input '" "@example.com'
Code src/validators/email.py:93-95 — the quoted-string character class [... !#-\[\]-\177] omits 0x20 (space), which RFC 5321 qtextSMTP (%d32-33) allows.
Upstream no existing issue found (searched python-validators/validators issues on 2026-09-26); still present on master.
emailnew1 test entry
IPv6 address literal with IPv6: tag is rejected
Input 'user@[IPv6:::1]' with ipv6_address=True / 'user@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]' with ipv6_address=True
Code src/validators/email.py:70 — domain_part.lstrip("[").rstrip("]") keeps the IPv6: tag, so the RFC 5321 form [IPv6:::1] is rejected while the non-standard [::1] is accepted.
Upstream no existing issue found (searched 2026-09-26); still present on master.
financeknown upstream4 test entries
ISIN checksum never accumulates — _isin_checksum loop does not update check
Input "US0378331006" (wrong check digit; correct is "US0378331005")
Code src/validators/finance.py:34-51 — _isin_checksum computes val but never adds it to check, so return (check % 10) == 0 is always True and any check digit is accepted.
Upstream known bug, issue #440 (open) with open fix PRs #464, #468 and #473; still present on master. MutantHunter rediscovered it from the spec, it is not new.
hostnamenew1 test entry
Simple hostname regex caps at 61 characters instead of 63
Input "a" * 62 (and "a" * 63)
Code src/validators/hostname.py:27-29 — [a-z0-9-]{0,59} between the first and last character caps a single-label hostname at 61 characters; RFC 1123 section 2.1 requires up to 63. Labels inside a dotted name are checked by domain() and are not affected.
Upstream no issue for this cap (related feature request #433 on RFC 1123 support); still present on master.
urlnew1 test entry
Empty port (trailing colon) rejected by implementation
Input "http://example.com:"
Code src/validators/hostname.py:18-21 — the port regex requires at least one digit, but RFC 3986 section 3.2.3 defines port = *DIGIT and the WHATWG URL standard also accepts http://example.com:. Minor severity.
Upstream no existing issue found (searched 2026-09-26); still present on master.
All suspected violations (13), raw entries
email: Quoted-string local part with space is rejected logic · confirmed
## SV-1: Quoted-string local part with space is rejected
- Category: logic
- Spec: RFC 5321 4.1.2 — R6
- Input: `'" "@example.com'`
- Spec says: valid — qtextSMTP is `%d32-33 / %d35-91 / %d93-126`; space (0x20 = %d32) is explicitly permitted inside a quoted-string
- Code returns: `ValidationError` (falsy)
- Test:
```python
from validators import email
assert email('" "@example.com')
```
- Status: confirmed
- Bug: email-quoted-local-part
- Code: `src/validators/email.py:93-95` — the quoted-string character class `[... !#-\[\]-\177]` omits 0x20 (space), which RFC 5321 qtextSMTP (`%d32-33`) allows.
- Upstream: no existing issue found (searched python-validators/validators issues on 2026-09-26); still present on master.
- Same root cause as SV-4 (quoted-string handling); counted once.
- Broad-test removed: `test_quoted_string_with_space` — asserted current behavioremail: Single-character TLD is rejected logic · rejected
## SV-2: Single-character TLD is rejected
- Category: logic
- Spec: RFC 5321 4.1.2 / RFC 1034 — R7
- Input: `'user@example.a'`
- Spec says: valid — neither RFC 5321 nor RFC 1034 imposes a minimum TLD length; a single-label TLD is syntactically legal
- Code returns: `ValidationError` (falsy)
- Test:
```python
from validators import email
assert email("user@example.a")
```
- Status: rejected
- Review: design choice, not a logic bug. The library requires a TLD of 2-63 letters (see upstream PR #476, which kept that rule), and no single-character TLD exists in the DNS root.email: IPv6 address literal with IPv6: tag is rejected logic · confirmed
## SV-3: IPv6 address literal with `IPv6:` tag is rejected
- Category: logic
- Spec: RFC 5321 4.1.3 — R11
- Input: `'user@[IPv6:::1]'` with `ipv6_address=True` / `'user@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]'` with `ipv6_address=True`
- Spec says: valid — IPv6 literals in email domains MUST use the `IPv6:` prefix inside brackets; `[IPv6:::1]` and `[IPv6:2001:…]` are the correct form
- Code returns: `ValidationError` (falsy) — the implementation strips brackets with `lstrip("[").rstrip("]")`, leaving `IPv6:::1`, but then passes it directly to the `hostname` validator which does not know how to handle the `IPv6:` prefix
- Test:
```python
from validators import email
assert email("user@[IPv6:::1]", ipv6_address=True)
assert email("user@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]", ipv6_address=True)
```
- Status: confirmed
- Bug: email-ipv6-literal
- Code: `src/validators/email.py:70` — `domain_part.lstrip("[").rstrip("]")` keeps the `IPv6:` tag, so the RFC 5321 form `[IPv6:::1]` is rejected while the non-standard `[::1]` is accepted.
- Upstream: no existing issue found (searched 2026-09-26); still present on master.email: Quoted-string local part containing @ or special characters is rejected logic · confirmed
## SV-4: Quoted-string local part containing `@` or special characters is rejected
- Category: logic
- Spec: RFC 5322 3.2.4 / RFC 5321 4.1.2 — R6
- Input: `'"user@name"@example.com'` / `'"user name"@example.com'`
- Spec says: valid — any printable ASCII character except unescaped `"` and `\` is allowed inside a quoted-string, including `@`, spaces, and `(`, `)`, `,`, `;`, `<`, `>`, `:`
- Code returns: `ValidationError` (falsy) — for `@` inside quotes, the count-`@` check at line 58 rejects addresses with more than one `@`; for spaces, the quoted-string regex character class omits 0x20
- Test:
```python
from validators import email
assert email('"user name"@example.com')
assert email('"user@name"@example.com')
```
- Status: confirmed
- Bug: email-quoted-local-part
- Code: `src/validators/email.py:58` — `value.count("@") != 1` rejects any `@` inside a quoted local part before the quoted-string regex runs; spaces fail at `email.py:93-95` (see SV-1).
- Upstream: no existing issue found (searched 2026-09-26); still present on master.
- Same root cause as SV-1; counted once together with SV-1.finance: ISIN checksum never accumulates — _isin_checksum loop does not update check logic · confirmed
## ISIN checksum never accumulates — `_isin_checksum` loop does not update `check`
- Category: logic
- Spec: wiki-ISIN.txt § Examples — R21
- Input: `"US0378331006"` (wrong check digit; correct is `"US0378331005"`)
- Spec says: invalid (Luhn check digit must be 5, not 6)
- Code returns: True (check is always 0 because the loop never adds val to check)
- Test:
```python
from validators import isin
def test_isin_invalid_wrong_check_digit_apple():
"""Spec: wiki-ISIN.txt § Examples — Apple, Inc. — R21
'US0378331006' (check digit 6 instead of 5) must be invalid.
"""
assert not isin("US0378331006")
```
- Status: confirmed
- Bug: isin-check-digit
- Code: `src/validators/finance.py:34-51` — `_isin_checksum` computes `val` but never adds it to `check`, so `return (check % 10) == 0` is always True and any check digit is accepted.
- Upstream: known bug, issue #440 (open) with open fix PRs #464, #468 and #473; still present on master. MutantHunter rediscovered it from the spec, it is not new.
- The other three ISIN entries below have the same root cause; the four entries count as one bug.
- Broad-test removed: `test_isin_wrong_checksum_passes_due_to_bug` — asserted current behaviorfinance: ISIN checksum never accumulates — last char letter incorrectly accepted logic · confirmed
## ISIN checksum never accumulates — last char letter incorrectly accepted
- Category: logic
- Spec: wiki-ISIN.txt § Description — R16
- Input: `"US037833100A"` (last character is letter 'A', not a digit)
- Spec says: invalid (last character must be a numerical check digit 0–9)
- Code returns: True (check is always 0 because the loop never adds val to check)
- Test:
```python
from validators import isin
def test_isin_last_char_letter_is_invalid():
"""Spec: wiki-ISIN.txt § Description — R16
An ISIN whose last character is a letter rather than a digit must be invalid.
"""
assert not isin("US037833100A")
```
- Status: confirmed
- Bug: isin-check-digit
- Review: same root cause as the first ISIN entry (#440); counted once.
- Broad-test removed: `test_isin_12_letter_string_passes_due_to_bug` — asserted current behaviorfinance: ISIN checksum never accumulates — wrong check digit for Treasury Corp Victoria logic · confirmed
## ISIN checksum never accumulates — wrong check digit for Treasury Corp Victoria
- Category: logic
- Spec: wiki-ISIN.txt § Examples — R21
- Input: `"AU0000XVGZA4"` (wrong check digit; correct is `"AU0000XVGZA3"`)
- Spec says: invalid (Luhn check digit must be 3, not 4)
- Code returns: True
- Test:
```python
from validators import isin
def test_isin_invalid_wrong_check_digit_treasury():
"""Spec: wiki-ISIN.txt § Examples — Treasury Corp Victoria — R21
'AU0000XVGZA4' (check digit 4 instead of 3) must be invalid.
"""
assert not isin("AU0000XVGZA4")
```
- Status: confirmed
- Bug: isin-check-digit
- Review: same root cause as the first ISIN entry (#440); counted once.finance: ISIN checksum never accumulates — wrong check digit for BAE Systems logic · confirmed
## ISIN checksum never accumulates — wrong check digit for BAE Systems
- Category: logic
- Spec: wiki-ISIN.txt § Examples — BAE Systems — R21
- Input: `"GB0002634947"` (wrong check digit; correct is `"GB0002634946"`)
- Spec says: invalid (correct check digit is 6)
- Code returns: True
- Test:
```python
from validators import isin
def test_isin_invalid_wrong_check_digit_bae():
"""Spec: wiki-ISIN.txt § Examples — BAE Systems — R21
'GB0002634947' (check digit 7 instead of 6) must be invalid.
"""
assert not isin("GB0002634947")
```
- Status: confirmed
- Bug: isin-check-digit
- Review: same root cause as the first ISIN entry (#440); counted once.hostname: Simple hostname regex caps at 61 characters instead of 63 logic · confirmed
## Simple hostname regex caps at 61 characters instead of 63
- Category: logic
- Spec: rfc1123.pdf Section 2.1 — R8
- Input: `"a" * 62` (and `"a" * 63`)
- Spec says: valid — RFC 1123 §2.1 states "Host software MUST handle host names of up to 63 characters"
- Code returns: `ValidationError` — the `_simple_hostname_regex` in `hostname.py` uses `{0,59}` for the middle segment which, combined with the mandatory first char and optional last char, caps the total at 61 characters (1 + 59 + 1 = 61). The comment in the source even acknowledges the range should be `{1, 61}` but that is already incorrect per the spec (should be `{1, 63}`).
- Test:
```python
def test_label_63_chars_valid():
label = "a" * 63
assert hostname(label)
def test_label_62_chars_valid():
label = "a" * 62
assert hostname(label)
def test_label_63_chars_with_hyphen_valid():
label = "a" + "b" * 61 + "c" # 63 chars total
assert hostname(label)
```
- Broad-test removed: `test_simple_62_chars_invalid` — asserted current behavior (62-char label invalid)
- Status: confirmed
- Bug: hostname-63-characters
- Code: `src/validators/hostname.py:27-29` — `[a-z0-9-]{0,59}` between the first and last character caps a single-label hostname at 61 characters; RFC 1123 section 2.1 requires up to 63. Labels inside a dotted name are checked by `domain()` and are not affected.
- Upstream: no issue for this cap (related feature request #433 on RFC 1123 support); still present on master.mac_address: Dot-grouped notation not supported (three groups of four hex digits) logic · rejected
## Dot-grouped notation not supported (three groups of four hex digits)
- Category: logic
- Spec: wiki-MAC_address.pdf Notational conventions — R4
- Input: `"0123.4567.89AB"`
- Spec says: valid (three groups of four hexadecimal digits separated by dots is an accepted human-friendly notation)
- Code returns: `ValidationError(func=mac_address, args={'value': '0123.4567.89AB'})`
- Test:
```python
from validators import mac_address
def test_dot_notation_basic():
assert mac_address("0123.4567.89AB")
def test_dot_notation_lowercase():
assert mac_address("0123.4567.89ab")
def test_dot_notation_mixed_case():
assert mac_address("aAbB.cCdD.eEfF")
def test_dot_notation_all_zeros():
assert mac_address("0000.0000.0000")
def test_dot_notation_broadcast():
assert mac_address("FFFF.FFFF.FFFF")
```
- Status: rejected
- Review: scope choice, not a logic bug. The docstring and regex only promise colon- and hyphen-separated addresses; the spec lists the dotted form as an alternative convention, not the IEEE 802 standard format.
---
### Root cause
The validator's regex `^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$` only
matches six 2-digit groups separated by `:` or `-`.
It does not include a branch for three 4-digit groups separated by `.`
(`^([0-9A-Fa-f]{4}\.){2}([0-9A-Fa-f]{4})$`), which the Wikipedia
Notational conventions section explicitly lists as a valid notation (Cisco
format, e.g. `0123.4567.89AB`).url: Port zero rejected by implementation logic · rejected
## Port zero rejected by implementation
- Category: logic
- Spec: rfc3986 §3.2.3 — R14
- Input: `"http://example.com:0/path"`
- Spec says: valid — `port = *DIGIT`; port 0 is a single digit and is syntactically legal per the RFC grammar
- Code returns: `ValidationError` — the hostname validator rejects port 0 (treats it as invalid rather than applying a pure syntax check)
- Test:
```python
from validators import url
def test_port_zero():
"""Spec: rfc3986 §3.2.3 — R14: port 0 is syntactically valid per *DIGIT grammar."""
assert url("http://example.com:0/path")
```
- Status: rejected
- Review: design choice. `src/validators/hostname.py:18-21` deliberately accepts ports 1-65535; port 0 is reserved and cannot be connected to, so rejecting it is a semantic policy beyond RFC 3986 syntax.url: Empty port (trailing colon) rejected by implementation logic · confirmed
## Empty port (trailing colon) rejected by implementation
- Category: logic
- Spec: rfc3986 §3.2.3 — R14
- Input: `"http://example.com:"`
- Spec says: valid — `port = *DIGIT` allows zero digits; RFC 3986 §3.2.3 says producers SHOULD omit the `:` when port is empty but parsers must accept it
- Code returns: `ValidationError` — the hostname validator rejects a trailing `:` with no port digits
- Test:
```python
from validators import url
def test_port_empty_is_spec_valid():
"""Spec: rfc3986 §3.2.3 — R14: port = *DIGIT; empty port (host:) is syntactically valid."""
assert url("http://example.com:")
```
- Status: confirmed
- Bug: url-empty-port
- Code: `src/validators/hostname.py:18-21` — the port regex requires at least one digit, but RFC 3986 section 3.2.3 defines `port = *DIGIT` and the WHATWG URL standard also accepts `http://example.com:`. Minor severity.
- Upstream: no existing issue found (searched 2026-09-26); still present on master.url: Strict-query rejects RFC-valid pchar characters in query (: and @) spec-ambiguous · rejected
## Strict-query rejects RFC-valid pchar characters in query (`:` and `@`)
- Category: spec-ambiguous
- Spec: rfc3986 §3.4 — R19
- Input: `"http://example.com/path?user:name@host"`
- Spec says: valid — `query = *(pchar / "/" / "?")` and `pchar` includes both `:` and `@`; the query string `user:name@host` is syntactically correct per RFC 3986
- Code returns: `ValidationError(reason="bad query field: 'user:name@host'")` — `parse_qs` with `strict_parsing=True` (the default) treats an unquoted field with no `=` separator as a parse error
- Test:
```python
from validators import url
def test_query_colon_at_allowed():
"""Spec: rfc3986 §3.4 — R19: ':' and '@' (pchar) are allowed in query."""
assert url("http://example.com/path?user:name@host")
```
- Status: rejected
- Review: policy choice exposed as the `strict_query` parameter (default True); with `strict_query=False` the input is accepted. The human tests encode the strict default.
- Note: The `strict_query=True` default is an application-level policy choice, not an RFC grammar rule. The human tests at `tests/test_url.py` are consistent with `strict_query=True` (e.g. they mark `?bar=baz&inga=42&quux` as invalid). This is therefore `spec-ambiguous` rather than a clear logic bug.