Skip to content

Length Validation — Complete Guide

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you'll learn about Length Validation. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Length validation checks that strings and collections have sizes within expected boundaries, preventing too-short or too-long inputs.

What You'll Learn

By the end of this lesson, you will validate string lengths, array lengths, byte sizes, and handle Unicode character length vs byte length differences.

Why It Matters

Without length limits, an attacker can send a 10MB JSON string and crash your server. Length validation prevents resource exhaustion and data truncation.

Real-World Use

Twitter's 280-character limit is a length validation. Without it, tweets could fill databases. The same principle applies to all user-generated content.

Length Validator

# length_validator.py
from typing import Any, Dict, List, Optional

class LengthValidator:
    @staticmethod
    def string(value: Any, min_len: Optional[int] = None,
               max_len: Optional[int] = None) -> Optional[str]:
        if not isinstance(value, str):
            return "Value must be a string"

        stripped = value.strip()

        if min_len is not None and len(stripped) < min_len:
            return f"Minimum {min_len} character{'s' if min_len != 1 else ''}"

        if max_len is not None and len(value) > max_len:
            return f"Maximum {max_len} character{'s' if max_len != 1 else ''}"

        return None

    @staticmethod
    def array(value: Any, min_items: Optional[int] = None,
              max_items: Optional[int] = None) -> Optional[str]:
        if not isinstance(value, (list, tuple)):
            return "Value must be an array"

        if min_items is not None and len(value) < min_items:
            return f"At least {min_items} item{'s' if min_items != 1 else ''} required"

        if max_items is not None and len(value) > max_items:
            return f"At most {max_items} item{'s' if max_items != 1 else ''} allowed"

        return None

    @staticmethod
    def byte_length(value: str, encoding: str = "utf-8",
                    max_bytes: Optional[int] = None) -> Optional[str]:
        if not isinstance(value, str):
            return "Value must be a string"

        if max_bytes is not None:
            byte_len = len(value.encode(encoding))
            if byte_len > max_bytes:
                return f"Maximum {max_bytes} bytes (current: {byte_len})"

        return None

lv = LengthValidator()
print(f"String 'Hi' (2-10):  {lv.string('Hi', 2, 10)}")
print(f"String 'A' (min 2):  {lv.string('A', 2)}")
print(f"String long (max 5): {lv.string('Hello World', max_len=5)}")
print(f"Array [1,2] (1-3):   {lv.array([1, 2], 1, 3)}")
print(f"Array [] (min 1):    {lv.array([], min_items=1)}")
print(f"Bytes 'Hello' (max 10): {lv.byte_length('Hello', max_bytes=10)}")
print(f"Bytes 'Hello!' (max 5): {lv.byte_length('Hello!', max_bytes=5)}")

Expected output:

String 'Hi' (2-10):  None
String 'A' (min 2):  Minimum 2 characters
String long (max 5): Maximum 5 characters
Array [1,2] (1-3):   None
Array [] (min 1):    At least 1 item required
Bytes 'Hello' (max 10): None
Bytes 'Hello!' (max 5): Maximum 5 bytes (current: 6)

Unicode Length Handling

# unicode_length.py
from typing import Any, Optional

class UnicodeLengthValidator:
    @staticmethod
    def char_length(value: str) -> int:
        return len(value)

    @staticmethod
    def byte_length(value: str, encoding: str = "utf-8") -> int:
        return len(value.encode(encoding))

    @staticmethod
    def grapheme_clusters(value: str) -> int:
        import unicodedata
        count = 0
        for c in value:
            if unicodedata.combining(c) == 0:
                count += 1
            else:
                count += 1
        return count

    @staticmethod
    def validate(value: str, max_chars: Optional[int] = None,
                 max_bytes: Optional[int] = None) -> list:
        errors = []

        if max_chars and len(value) > max_chars:
            errors.append(f"Max {max_chars} characters ({len(value)} current)")

        if max_bytes:
            b = len(value.encode("utf-8"))
            if b > max_bytes:
                errors.append(f"Max {max_bytes} bytes ({b} current)")

        return errors

ulv = UnicodeLengthValidator()

tests = [
    "Hello",
    "cafe\u0301",  # cafe + combining accent (5 chars)
    "\U0001f600",  # emoji (1 char, 4 bytes)
]

for t in tests:
    chars = ulv.char_length(t)
    bytes_l = ulv.byte_length(t)
    print(f"  {t!r:20s} chars={chars} bytes={bytes_l}")

Expected output:

  'Hello'              chars=5 bytes=5
  'cafe\u0301'         chars=5 bytes=6
  '\U0001f600'         chars=1 bytes=4

Schema Length Rules

# schema_length.py
from typing import Any, Dict, List, Optional

class SchemaLengthValidator:
    def __init__(self):
        self.rules: Dict[str, Dict] = {}

    def string_field(self, name: str, min_len: int = 0, max_len: Optional[int] = None):
        self.rules[name] = {"type": "string", "min": min_len, "max": max_len}

    def array_field(self, name: str, min_items: int = 0, max_items: Optional[int] = None):
        self.rules[name] = {"type": "array", "min": min_items, "max": max_items}

    def validate(self, data: Dict) -> List[Dict]:
        errors = []
        for field, rule in self.rules.items():
            value = data.get(field)
            if value is None:
                continue

            if rule["type"] == "string":
                if not isinstance(value, str):
                    errors.append({"field": field, "code": "not_string"})
                else:
                    if rule["min"] and len(value) < rule["min"]:
                        errors.append({"field": field, "code": "min_length", "min": rule["min"]})
                    if rule["max"] and len(value) > rule["max"]:
                        errors.append({"field": field, "code": "max_length", "max": rule["max"]})

            elif rule["type"] == "array":
                if not isinstance(value, (list, tuple)):
                    errors.append({"field": field, "code": "not_array"})
                else:
                    if rule["min"] and len(value) < rule["min"]:
                        errors.append({"field": field, "code": "min_items", "min": rule["min"]})
                    if rule["max"] and len(value) > rule["max"]:
                        errors.append({"field": field, "code": "max_items", "max": rule["max"]})

        return errors

sv = SchemaLengthValidator()
sv.string_field("username", min_len=3, max_len=30)
sv.array_field("tags", min_items=1, max_items=5)

print(sv.validate({"username": "ab", "tags": []}))
print(sv.validate({"username": "alice", "tags": ["api"]}))

Expected output:

[{'field': 'username', 'code': 'min_length', 'min': 3}, {'field': 'tags', 'code': 'min_items', 'min': 1}]
[]

Common Mistakes

1. Not Trimming Before Length Check

" Hi " is 8 characters but only 2 meaningful. Trim first, then check length.

2. Confusing Character and Byte Length

Unicode characters can be 1-4 bytes. Use character count for UX, byte count for storage.

3. Same Length for All Fields

Username (3-30), bio (0-500), title (1-200) — each field needs its own length.

4. No Upper Limit

No max length allows DoS attacks with massive inputs. Always set a maximum.

5. Ignoring Array Length

Arrays without item limits can receive millions of items. Always set max_items.

Practice Questions

1. What is the difference between character and byte length?

Character length counts visible characters. Byte length counts storage size. Emojis are 1 char but 4 bytes.

2. Why trim before length check?

Leading/trailing whitespace inflates the count. Trim to get meaningful content length.

**3. What is a safe maximum string length for API inputs?"

Depends on the field. Usernames: 30. Emails: 254. Bios: 500. Always research reasonable limits.

4. Why validate array lengths?

Prevent DoS: a 100,000-item array could crash your server. Set reasonable max_items.

Challenge

Build a length validation system for a blog post: title (5-200 chars), slug (3-100 chars), content (100-50000 chars), tags (1-10 items), meta_description (0-320 chars).

FAQ

What is the max length for email addresses?

254 characters per RFC 5321. Most APIs set 254 as the maximum.

Should I validate length on the database column?

Yes, as a last resort. Validate in application code for better error messages.

How do I handle Unicode length in databases?

MySQL VARCHAR counts characters (not bytes) with utf8mb4. PostgreSQL TEXT has no practical limit.

What is the minimum useful password length?

8 characters minimum. 12+ is recommended for sensitive applications.

Can length validation prevent SQL injection?

No. SQL injection requires proper escaping/parameterization. Length limits help but are not sufficient.

Mini Project: Length Manager

# length_mgr.py
from typing import Any, Dict, List, Optional

def check_length(value: Any, field: str, min_v: int = 0, max_v: Optional[int] = None) -> Optional[str]:
    if min_v and len(value) < min_v:
        return f"{field}: min {min_v}"
    if max_v and len(value) > max_v:
        return f"{field}: max {max_v}"
    return None

print(check_length("ab", "name", 3, 50))
print(check_length("Alice", "name", 3, 50))

Expected output:

name: min 3
None

What's Next

You understand length validation. Next, learn regex validation, then cross-field validation.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro