Cannot Insert the Value NULL Into Column (Error 515)

🚨Part of the SQL Server Errors series, the exact messages and what actually causes them.

Msg 515  ·  Level 16  ·  State 2
Cannot insert the value NULL into column ‘CustomerID’, table ‘SalesDB.dbo.Orders’; column does not allow nulls. INSERT fails. The statement has been terminated.
You may not have written NULL anywhere. Leaving a NOT NULL column out of the column list produces this identical message, because SQL Server has nothing to put there and calls that nothing NULL. Check the named column against your column list before you go looking for NULLs in the data.

The message names the column and the table, which is genuinely helpful, and then describes a NULL that in most real cases nobody ever typed. There are two ways to get here and they need different fixes.


Cause One: You Really Did Insert a NULL

The obvious one. A value in the statement, or a column in the source of an INSERT ... SELECT, is NULL and the target column does not allow it:

INSERT INTO dbo.Orders (OrderID, CustomerID, OrderDate)
VALUES (1, NULL, SYSDATETIME());        -- Msg 515 on CustomerID

When it comes from a SELECT, the NULL is usually arriving from an outer join that did not match, or from a source column that is nullable when the target is not. Find it before you change anything:

SELECT COUNT(*) AS rows_with_nulls
FROM   Staging.dbo.Orders
WHERE  CustomerID IS NULL;

Cause Two: You Left the Column Out Entirely

This is the one that wastes an afternoon. The statement below never mentions NULL, and it produces the same Msg 515 naming CustomerID:

INSERT INTO dbo.Orders (OrderID, OrderDate)
VALUES (2, SYSDATETIME());              -- Msg 515, and there is no NULL in sight

SQL Server has nothing to put in CustomerID, the column will not accept nothing, and the nothing gets reported as NULL. Verified on SQL Server 2025: both statements return a byte-identical message.

So the first thing to do with a 515 is not to hunt for NULLs in the data. It is to compare the column the message names against the column list you actually wrote.


A Default Fixes One of Them and Not the Other

Adding a default constraint is the usual advice, and it only solves the second cause. Tested, both statements, against the same table with a default in place:

ALTER TABLE dbo.Orders
ADD CONSTRAINT DF_Orders_CustomerID DEFAULT (0) FOR CustomerID;

-- column omitted: now SUCCEEDS, the row lands with CustomerID = 0
INSERT INTO dbo.Orders (OrderID, OrderDate) VALUES (3, SYSDATETIME());

-- explicit NULL: STILL Msg 515
INSERT INTO dbo.Orders (OrderID, CustomerID, OrderDate) VALUES (4, NULL, SYSDATETIME());

A default applies when the column is absent, not when it is present and NULL. Passing NULL explicitly is you saying “put NULL here”, and the default never gets a look in. That catches out anything generated by an ORM or a mapping layer, which usually sends every column whether it has a value or not.

Microsoft’s reference covers ALTER TABLE and Specify default values for columns in full.


The Fixes, and Which One To Reach For

In the order you should consider them:

-- 1. supply the value. Usually the right answer.
INSERT INTO dbo.Orders (OrderID, CustomerID, OrderDate) VALUES (5, 42, SYSDATETIME());

-- 2. give the column a sensible default, if one genuinely exists
ALTER TABLE dbo.Orders ADD CONSTRAINT DF_Orders_Status DEFAULT ('New') FOR Status;

-- 3. coalesce a nullable source column on the way in
INSERT INTO dbo.Orders (OrderID, CustomerID, OrderDate)
SELECT OrderID, ISNULL(CustomerID, 0), OrderDate FROM Staging.dbo.Orders;

-- 4. last resort: let the column be nullable, and mean it
ALTER TABLE dbo.Orders ALTER COLUMN CustomerID int NULL;

Option four is the one to be careful with. NOT NULL is usually there on purpose, and relaxing it to clear an error moves the problem into your data, where it will be someone else’s problem later. If the column truly is optional, that is a schema decision worth making deliberately rather than at 5pm.


The One That Is Not 515

Adding a NOT NULL column to a table that already contains rows feels like the same problem and produces a different error:

Msg 4901  ·  Level 16  ·  State 1
ALTER TABLE only allows columns to be added that can contain nulls, or have a DEFAULT definition specified, or the column being added is an identity or timestamp column, or alternatively if none of the previous conditions are satisfied the table must be empty to allow addition of this column.

Verified on SQL Server 2025. The fix is to add the column with a default in the same statement, which then applies to every existing row:

ALTER TABLE dbo.Orders
ADD Status varchar(20) NOT NULL CONSTRAINT DF_Orders_Status DEFAULT ('New');

Common Questions

The message names a column I did not touch.
Then you probably left it out. Omitting a NOT NULL column with no default gives the same message as inserting NULL into it. Compare the named column against your column list first, before looking at the data.
Why does my default constraint not work?
Because you are passing the column explicitly with a NULL value. A default only applies when the column is absent from the statement. Verified on SQL Server 2025: with a default in place, omitting the column succeeded and passing NULL still raised 515.
Did any rows get inserted before it failed?
For a single statement, no. The statement is terminated and the whole thing rolls back, so you do not get a partial row. A multi-row VALUES list is still one statement, so the same applies: all of it or none of it.
Should I just make the column nullable?
Only if it genuinely is optional. NOT NULL is a rule someone wrote down on purpose, and dropping it to clear an error pushes the problem into the data, where it becomes harder to find. Fix the insert first and change the schema only if the rule was wrong.
It is an ORM or an application doing the insert.
Then cause one is far more likely than cause two, because those layers usually send every column. Something in the object is null where the column is not nullable. The message names the column, which maps back to the property.

Related Scripts

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *