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.

Why it only fails in productionModel fieldmax_length=100Code saves140 charactersSQLiteignores the limitPostgreSQLrejects, DataErrorSQLite stores any length, so length bugs only surface on PostgreSQL or MySQL in production.
  1. Find the field: the error does not name it, so log the data or check which CharFields have that max_length.
  2. Decide: is the input wrong (validate and reject it) or is the limit too small (raise max_length)?
  3. To raise the limit, change max_length and run makemigrations and migrate; on PostgreSQL, widening a varchar is fast.
  4. Validate length where data enters: forms and DRF serializers do it automatically, objects.create() and imports do not.
  5. 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 (URLField defaults to 200, real URLs with tracking parameters exceed it), email subjects, product titles from suppliers, user agents. Raise the limit or use TextField.

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.

CharField(max_length=100) given 140 charactersResultRiskSQLite!stores all 140hides the bug locallyPostgreSQL✓DataErrorfails loudlyMySQL strict mode✓error 1406fails loudlyMySQL non-strict✕truncates silentlydata lossDevelop on the same database you deploy todjango-deployment.com
PostgreSQL failing loudly is the safe behaviour; the bug was always in the code or data.

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).

long values handled on purposeField identified from logs or payloaderror omits the columnLimit raised with a migration if too smallwidening is fast on PostgresImports call full_clean or truncatecreate() skips validationTextField where no real limit existssame storage on PostgresTests run on PostgreSQLSQLite hides length bugsThe database caught a validation gap; close it in the codedjango-deployment.com
Running CI against PostgreSQL catches these before users do.

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 utf8mb4 also counts characters for varchar.
  • Unique indexes. Very long varchar values 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

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.

Keep going