# Npgsql PostgresException 22001: value too long for type character varying(n)

PostgreSQL rejects the write because a string exceeds the column's declared length. The error names the type and the limit but not the column, so the practical work is identifying which parameter overflowed — and PostgreSQL counts characters, not bytes.

> Confidence: high · Verified: 2026-08-07 · Status: fresh · Source: https://knowbase.sh/k/npgsql-22001-string-data-right-truncation

## Error signature

```
22001: value too long for type character varying(n)
```

Codes: 22001, string_data_right_truncation

## Problem

An INSERT or UPDATE through Npgsql throws Npgsql.PostgresException with SqlState 22001. The message reports the column type and its length but not which column failed, and with Entity Framework Core batching several rows into one round trip, it is not obvious which entity or property caused it.

## Root cause

- **The value is genuinely longer than the column's declared length** _(primary)_
  - PostgreSQL enforces varchar(n) as a hard constraint and rejects the statement rather than silently truncating, unlike some other engines running in a permissive mode.
  - How to tell: The offending .NET string's Length exceeds the n reported in the message
- **The EF Core model does not declare a maximum length that matches the schema** _(common)_
  - Without HasMaxLength or a MaxLength attribute, EF Core will not validate on the client, so an over-long value travels to the server and fails there. The reverse also happens after schema drift, where the model says 200 and the table still says 50.
  - How to tell: The property has no MaxLength in the model, or its value disagrees with information_schema.columns
- **The column is char(n) rather than varchar(n)** _(common)_
  - char(n) is blank-padded to exactly n characters. Trailing whitespace that looks harmless still counts toward the limit and triggers the same error.
  - How to tell: The message says 'character(n)' rather than 'character varying(n)'
- **Character count confused with byte count** _(common)_
  - PostgreSQL's n in varchar(n) counts characters, not bytes. Columns sized from a byte budget are wrong in both directions — too small for multi-byte text sized in bytes, and unexpectedly permissive when developers assume the opposite.
  - How to tell: The string's character length is at or under n but its UTF-8 byte length is larger
- **An explicit parameter Size smaller than the value** _(edge)_
  - Setting NpgsqlParameter.Size or an explicit NpgsqlDbType with a narrower width can truncate ahead of the server.
  - How to tell: The failure disappears when the explicit Size is removed from the parameter

## Solution

1. Catch the exception as PostgresException and read SqlState rather than matching on the message text, which is localised and version-dependent.

```csharp
try
{
    await db.SaveChangesAsync();
}
catch (PostgresException ex) when (ex.SqlState == PostgresErrorCodes.StringDataRightTruncation)
{
    // 22001 — a value exceeded its column's declared length
    logger.LogError(ex, "Truncation on {Table}", ex.TableName);
    throw;
}
```

   Note: PostgresException always populates SqlState; TableName and ColumnName are only present for error classes where the server supplies them, and 22001 generally does not identify the column.
2. Find the offending column by comparing the declared widths against the lengths you are actually sending.

```bash
psql -c "SELECT column_name, data_type, character_maximum_length FROM information_schema.columns WHERE table_name = 'your_table' ORDER BY character_maximum_length"
```

3. Decide whether the schema or the input is wrong. If the limit is a real business rule, validate before the database call so the user gets a field-level message instead of a 500.

```csharp
modelBuilder.Entity<Customer>()
    .Property(c => c.DisplayName)
    .HasMaxLength(200)
    .IsRequired();
```

4. If the limit is arbitrary, widen the column. In PostgreSQL, increasing a varchar's length does not rewrite the table and takes only a brief lock.

```bash
ALTER TABLE customers ALTER COLUMN display_name TYPE varchar(500);
```

5. If there is no business limit at all, use text. In PostgreSQL text and varchar share an implementation, so text carries no performance penalty over varchar(n).
6. Size columns in characters, not bytes, and verify with length() versus octet_length() when the data is multi-byte.

```bash
SELECT length(val) AS chars, octet_length(val) AS bytes FROM t WHERE id = 1;
```


**Verify:** Re-run the failing write; it should succeed, and a deliberately over-long value should now be rejected by model validation with a field-level error rather than reaching PostgreSQL.

**If that fails:** Where the input legitimately exceeds the limit and cannot be rejected — imported third-party data, for example — truncate explicitly at the application boundary and record that truncation, rather than widening a column that encodes a real contract.

## Applies to

- PostgreSQL: 9.0 and later — SQLSTATE 22001 is string_data_right_truncation in class 22, Data Exception.
- Npgsql: 4.0 and later — PostgresException.SqlState is always present; PostgresErrorCodes exposes named constants.
- Entity Framework Core: 3.1 and later — Client-side length validation only happens when the model declares a maximum length.
- Runtimes: .NET 6, .NET 8, .NET 9

## Not applicable to

- SQLSTATE 23505 unique_violation, which is a duplicate key rather than a length problem
- SQL Server error 8152 or 2628, which is the same class of failure in a different engine with different semantics
- Numeric overflow, which raises 22003 numeric_value_out_of_range
- PostgreSQL text columns, which have no declared length limit and cannot raise this error

## Evidence

1. [PostgreSQL Error Codes (Appendix A)](https://www.postgresql.org/docs/current/errcodes-appendix.html) — The PostgreSQL Global Development Group (official-docs), read 2026-08-07
   Supports: That SQLSTATE 22001 is named string_data_right_truncation and belongs to class 22, Data Exception.
   > 22001 string_data_right_truncation
2. [PostgreSQL Character Types](https://www.postgresql.org/docs/current/datatype-character.html) — The PostgreSQL Global Development Group (official-docs), read 2026-08-07
   Supports: That varchar(n) rejects over-long values rather than truncating, that char(n) is blank-padded, that n is measured in characters, and that text and varchar perform identically.
   > There is no performance difference among these three types, apart from increased storage space when using the blank-padded type
3. [Npgsql PostgresException API reference](https://www.npgsql.org/doc/api/Npgsql.PostgresException.html) — Npgsql (official-docs), read 2026-08-07
   Supports: That PostgresException exposes SqlState, always populated, alongside TableName, ColumnName, and ConstraintName, which are populated only when the server supplied them.
   > If the error was associated with a specific table column, the name of the column.
4. [PostgreSQL Error and Notice Message Fields](https://www.postgresql.org/docs/current/protocol-error-fields.html) — The PostgreSQL Global Development Group (specification), read 2026-08-07
   Supports: That the column name field is only supplied for specific error classes, which is why 22001 typically arrives without naming the column that overflowed.
   > The fields for schema name, table name, column name, data type name, and constraint name are supplied only for a limited number of error types

## Confidence

high — The error code, the character-versus-byte semantics, and the varchar/text equivalence are stated directly in PostgreSQL's own reference, and the exception surface is taken from Npgsql's API documentation. The claim that 22001 usually omits the column name follows from the protocol's error-field rules rather than from an explicit sentence about 22001, so it is stated as a tendency, not a guarantee.

---

Retrieved from https://knowbase.sh/k/npgsql-22001-string-data-right-truncation · knowbase · CC-BY-4.0
