Fix it now
A value being written is wider than the column that has to hold it, and on the bare 8152 message SQL Server names neither. SQL Server 2019 and later raise a different error, 2628, which names the table, the column and the truncated value.
SELECT name, compatibility_level FROM sys.databases WHERE name = DB_NAME();
SELECT [value] FROM sys.database_scoped_configurations
WHERE [name] = 'VERBOSE_TRUNCATION_WARNINGS';
ALTER DATABASE SCOPED CONFIGURATION SET VERBOSE_TRUNCATION_WARNINGS = ON;
- Re-run the insert. At compatibility level 150 or higher you now get error 2628 instead of 8152, and it names the table, the column and the value that would not fit.
- At compatibility level 140 or lower the scoped configuration has no effect at all. Trace flag 460 is the only route to 2628 on those databases.
- With the column named, compare the two sides:
SELECT MAX(LEN(SomeText)), MAX(DATALENGTH(SomeText)) FROM dbo.Source;againstmax_lengthinsys.columnsfor the target. - Widen the target with
ALTER TABLE dbo.Target ALTER COLUMN SomeText nvarchar(200) NULL;, or cut the source deliberately withLEFT(col, n).
max_length in sys.columns counts bytes. An nvarchar column stores two bytes per character, so a column that holds 100 characters reports 200.
If the column is named and widened you are done. If the error is 245, 241, 8115 or 232 instead, it is a type problem rather than a width one and the next section separates them.
Why it happens
8152 is checked value by value inside the storage engine, which knows only that a value did not fit. The published message is the whole message: String or binary data would be truncated. No table, no column, no value. On a forty-column insert that sentence is the same regardless of which column overflowed, which is why the error has the reputation it has.
SQL Server 2019 introduced a second message for the same condition. Error 2628 reads String or binary data would be truncated in table '%.*ls', column '%.*ls'. Truncated value: '%.*ls'. Which of the two you get is decided by the VERBOSE_TRUNCATION_WARNINGS database scoped configuration, and by the database compatibility level. At level 150 and higher the setting decides, and its default is ON, so a modern database on a modern build already tells you the answer. At level 140 and lower the setting does nothing whatever and 2628 remains opt-in behind trace flag 460. That split is the part people get wrong: turning the configuration on in a database still running at 130 changes nothing at all.
The rest of this family is not about width. 245 is Conversion failed when converting the %ls value to data type %ls, and it fires for any value that will not convert to the target type, not only strings to numbers. 241 is the date and time parser refusing a string. 8115 is an arithmetic overflow during a conversion, 232 an arithmetic overflow for a type, and 8134 is division by zero. They arrive together because a single load statement can trip any of them, and telling them apart is the first thing to do.
The target column is genuinely narrower than the data
You have this one if 2628 names one column, and the maximum length in the source exceeds the declared width of that column.
- Widen it:
ALTER TABLE dbo.Target ALTER COLUMN SomeText nvarchar(200) NULL; - Check first what indexes and constraints reference the column, because a column in an index key cannot be widened past the index key size limit.
- If the data should never have been that long, fix the source and add a check constraint so the bad values stop arriving.
Widening is a metadata-only change in some cases and a full table rewrite in others. Time it on a copy before you run it on a large table in production.
A staging table inferred its widths from an expression
You have this one if The failure is inside a procedure that stages data, and the staging table was built by SELECT INTO or an implicit definition.
- Declare the temporary table explicitly with the widths you intend rather than letting SELECT INTO derive them.
- Watch concatenations and CASE expressions, whose result width comes from the branches and is often narrower than the real data.
- Cast the parts of a delimited string to a width you have chosen instead of relying on the default.
A varchar with no length is one character in a variable declaration and thirty in a CAST or CONVERT. Both defaults are documented, and both look perfectly reasonable when you read the code.
It is a type failure, not a width failure
You have this one if 245, 241, 8115 or 232 rather than 8152, on a column that is clearly the right size.
- Find the offending rows without failing the batch:
SELECT * FROM dbo.Source WHERE TRY_CONVERT(int, SomeText) IS NULL AND SomeText IS NOT NULL; - Use the same shape with
TRY_CONVERT(date, ...)for 241 and with the real target type for 245. - Convert explicitly at the point of the write rather than leaving an implicit conversion to the optimiser.
The source is Unicode and the target is not
You have this one if DATALENGTH on the source is roughly double LEN, and the target column is char or varchar.
- Move the target to
nvarcharif the data genuinely contains characters outside the target’s code page. - If the target must stay non-Unicode, establish what is being lost first: characters with no mapping in the code page are replaced, not preserved.
- Where the source is a file, confirm the encoding you read it with matches the encoding it was written in.
Full reference
Getting the message that names the column
| Compatibility level | VERBOSE_TRUNCATION_WARNINGS | Which error you get |
|---|---|---|
| 150 or higher | ON (the default) | 2628, naming table, column and truncated value |
| 150 or higher | OFF | 8152, the bare message |
| 140 or lower | Any value – the setting has no effect | 8152, unless trace flag 460 is enabled |
The scoped configuration is per database, so a server can behave differently from one database to the next, and a database restored from an older instance keeps the compatibility level it arrived with. If you have inherited an estate where some databases name the column and others do not, that pair of settings is why.
Measuring the two sides properly
SELECT c.name AS column_name, c.max_length, c.precision, c.scale, t.name AS type_name
FROM sys.columns AS c
JOIN sys.types AS t ON t.user_type_id = c.user_type_id
WHERE c.object_id = OBJECT_ID('dbo.Target')
ORDER BY c.column_id;
SELECT MAX(LEN(SomeText)) AS max_chars,
MAX(DATALENGTH(SomeText)) AS max_bytes
FROM dbo.Source;
LENreturns characters and ignores trailing spaces.DATALENGTHreturns bytes and counts everything.max_lengthinsys.columnsis in bytes, and is -1 for themaxtypes.- A
char(n)orvarchar(n)column stores n bytes for single-byte encodings; annvarchar(n)column stores two bytes per character. - Comparing characters against bytes is the commonest reason someone concludes a column is wide enough when it is not.
The other five codes, and what each is actually complaining about
| Error | Published message | What to look at |
|---|---|---|
| 8152 | String or binary data would be truncated | A character or binary value against a narrower column |
| 2628 | String or binary data would be truncated in table, column. Truncated value: | The same condition, with the answer included |
| 245 | Conversion failed when converting the value to data type | Any value the target type cannot accept, not only numbers |
| 241 | Conversion failed when converting date and/or time from character string | A string the date parser cannot read |
| 8115 | Arithmetic overflow error converting to data type | A numeric value outside the range of the type it is being converted to |
| 232 | Arithmetic overflow error for type, value = | An arithmetic result outside the range of its type |
| 8134 | Divide by zero error encountered | A zero divisor, often a denominator that is legitimately zero for some rows |
Do not switch SET ANSI_WARNINGS OFF to make 8152 stop. With that option off, the write can complete with the value silently shortened, so the load appears to succeed and the data is quietly damaged. A failed batch is a much better outcome than a table full of half-length values nobody notices for six months.
When the column is named and it still makes no sense
- Look for a trigger on the target. The overflow may be in the audit table the trigger writes to, not in the table you inserted into.
- Look for a computed column or a persisted expression whose result is wider than its declared type.
- Check
sql_variantanddynamicstaging patterns, where the effective type is decided at run time. - In a MERGE, the failing statement can be the UPDATE branch rather than the INSERT you were watching.
- If the write goes through a view, compare the view’s column definitions with the base table’s rather than assuming they agree.
Every code this article covers
| Code | What it points at | Source |
|---|---|---|
8152 |
String or binary data would be truncated. A character or binary value is wider than the target column, and this form of the message names neither | Microsoft Learn |
245 |
Conversion failed when converting the value to data type. Any value the target type will not accept, not only a string to a number | Microsoft Learn |
8115 |
Arithmetic overflow error converting to data type. A numeric conversion outside the range of the target | Microsoft Learn |
241 |
Conversion failed when converting date and/or time from character string | Microsoft Learn |
8134 |
Divide by zero error encountered | Microsoft Learn |
232 |
Arithmetic overflow error for type, with the value quoted. An arithmetic result outside the range of its type | Microsoft Learn |
Confirm the fix worked
- The failing statement now raises 2628 and names a table and a column, or it succeeds.
- The maximum
DATALENGTHin the source is at or belowmax_lengthfor the matching target column. - The insert completes and the row count in the target matches the row count in the source exactly.
- The longest values in the target read as complete rather than cut short.
SET ANSI_WARNINGSis still ON for the connection that runs the load.
Questions people ask about this
How do I get the message that names the column?
Put the database at compatibility level 150 or higher and leave VERBOSE_TRUNCATION_WARNINGS at its default of ON; that gives you error 2628 with the table, the column and the truncated value. Below level 140 the scoped configuration does nothing, and trace flag 460 is the only way to get 2628.
Why does LEN say the value fits when it clearly does not?
LEN counts characters and ignores trailing spaces. max_length in sys.columns counts bytes, and an nvarchar character occupies two of them. Compare DATALENGTH with max_length and the arithmetic works out.
Is there a cost to fixing this?
No. It is a schema and data problem and it behaves identically on every edition. Widening a column and cleaning source values cost nothing but the time to test them.
Can I just truncate the incoming values?
You can, with LEFT(col, n), but do it deliberately. The discarded characters are gone, and silent truncation is what causes the argument six months later about missing data.
Why did a CAST to varchar shorten my string to thirty characters?
Because a varchar with no length is thirty characters in CAST and CONVERT, and one character in a variable declaration. Both are documented defaults. Always give the length explicitly.
