Fix "value too long for type character varying" in Django
Fix Django DataError value too long for type character varying(N) on PostgreSQL: find the field and the input, raise max_length with a safe migration, validate in forms and serializers, and understand why SQLite never complained.
Problem statement
Saving a record in production raises:
django.db.utils.DataError: value too long for type character varying(100)
The same code worked in development. A CharField(max_length=100) creates a varchar(100) column in PostgreSQL, and PostgreSQL refuses strings longer than that. Something is writing longer values than the model allows: an import, an API client, a URL field, or code that sets the field directly without validation. SQLite, often used locally, ignores varchar length limits, which is why the problem appears only after deploying.
- Find the field: the error does not name it, so log the data or check which
CharFields have thatmax_length. - Decide: is the input wrong (validate and reject it) or is the limit too small (raise
max_length)? - To raise the limit, change
max_lengthand runmakemigrationsandmigrate; on PostgreSQL, widening avarcharis fast. - Validate length where data enters: forms and DRF serializers do it automatically,
objects.create()and imports do not. - Develop and test against PostgreSQL so this shows up before production.
Step-by-step solution
1. Identify the column
PostgreSQL's message gives the type but not the column. Enable the statement in the server log, or catch it in a shell reproduction:
from django.db import connection
from orders.models import Order
for f in Order._meta.get_fields():
if getattr(f, "max_length", None) == 100:
print(f.name)
Then compare with the payload that failed (from logs, Sentry, or the import file). PostgreSQL's server log with log_min_error_statement = error shows the failing INSERT or UPDATE with the column list.
2. Decide whether the data or the limit is wrong
- Data wrong: a name field receiving a whole address, or garbage from a scraper. Reject or truncate deliberately with a clear message.
- Limit too small: URLs (
URLFielddefaults to 200, real URLs with tracking parameters exceed it), email subjects, product titles from suppliers, user agents. Raise the limit or useTextField.
3. Raise max_length with a migration
class Product(models.Model):
title = models.CharField(max_length=255) # was 100
source_url = models.URLField(max_length=2000)
python manage.py makemigrations products
python manage.py sqlmigrate products 0012
The SQL is an ALTER TABLE ... ALTER COLUMN ... TYPE varchar(255). On PostgreSQL, increasing a varchar length or changing to text does not rewrite the table and is fast even on large tables, though it briefly takes an exclusive lock. Decreasing it requires checking every row.
4. Validate at the edges
Model forms and DRF serializers enforce max_length before saving. These paths do not:
Product.objects.create(title=row["title"]) # no validation
product.title = request.POST["title"]; product.save()
Product.objects.bulk_create([...])
Validate explicitly in imports and service functions:
p = Product(title=row["title"][:255]) # deliberate truncation, if acceptable
p.full_clean() # or validate and report the row
p.save()
For CSV or API imports, collect invalid rows and report them rather than failing the whole batch on one long value.
5. Choose TextField when there is no natural limit
PostgreSQL stores varchar(n) and text the same way, with no performance difference. If a field has no meaningful maximum (descriptions, notes, URLs), TextField avoids the issue entirely. Keep CharField with a limit where the limit is a real rule (country codes, SKUs, usernames).
Verification check: replay the failing input through the same code path on staging; it should either save or be rejected with a validation message, never with a DataError. python manage.py migrate --check should pass after deploying the migration.
Explanation
CharField.max_length serves two purposes: Django validation in forms and serializers, and the database column size. Validation only runs when something calls it, while the database constraint always applies. SQLite's type system is dynamic and accepts strings of any length in a varchar(100) column, so code that bypasses validation looks fine locally. PostgreSQL enforces the declared length strictly, turning the gap into an exception at save time in production.
Edge cases / notes
- Multibyte characters. PostgreSQL counts characters, not bytes, so emoji count as one; MySQL with
utf8mb4also counts characters forvarchar. - Unique indexes. Very long
varcharvalues in unique indexes can exceed PostgreSQL's index row size limit (about 2,700 bytes); consider a hash column. - Data migrations that copy data between fields can also hit limits; test them against a production-sized copy.
- Django admin uses model forms, so it validates; the error there points to a custom save method.
Next steps
- Large schema changes are covered in Django Schema Changes on Large Tables.
- For general 500 debugging, see Fix Django 500 Internal Server Error in Production.
FAQ
Why does this work on SQLite but fail on PostgreSQL?
SQLite does not enforce varchar lengths. PostgreSQL does.
Is it safe to increase max_length on a large table?
On PostgreSQL, increasing a varchar length or switching to text does not rewrite the table and is quick.
Is TextField slower than CharField on PostgreSQL?
No. Both are stored the same way. Use CharField when a maximum length is a real rule.
Why did validation not catch it?
objects.create(), save(), and bulk_create() do not run field validation. Only forms, serializers, and full_clean() do.