Conversion failed when converting date and/or time from character string. (error 241)
means SQL Server could not read a date written as text. Most often the text is fine but in the wrong
order for the session: '31/10/2026' is day-first, and a session in
us_english reads month-first, so month 31 does not exist.
Write date literals as ISO '2026-10-31' (or '20261031'), and from C# pass
a DateTime as a typed parameter instead of pasting text into the SQL.
SET DATEFORMAT dmy also works, as a last resort for one script.
The error
PS> .\FixLab.exe 'Server=(localdb)\MSSQLLocalDB;Database=fix7_lab;Integrated Security=true' "INSERT INTO dbo.Invoices (CustomerName, DueDate) VALUES ('Maria Garcia', '31/10/2026')"
ex.Number = 241, ex.Class = 16, ex.State = 1
Microsoft.Data.SqlClient.SqlException: Conversion failed when converting date and/or time from character string.
Why it happens
A string becomes a date according to the session's language, which sets its date order. In the
test database fix7_lab the session reported us_english and
mdy. After SET LANGUAGE British the same insert of
'31/10/2026' succeeded, and '10/31/2026' failed with the same error 241
instead. Nothing about the data changed, only who read it, which is why this error shows up when a
script moves to a server or login with a different default language.
The C# version of the mistake is building the SQL text with a formatted date. With the app's
culture set to en-GB, {dueDate:d} printed 31/10/2026 and the insert failed
exactly as above:
CultureInfo.CurrentCulture = new CultureInfo("en-GB");
var dueDate = new DateTime(2026, 10, 31);
var sql = $"INSERT INTO dbo.Invoices (CustomerName, DueDate) VALUES ('Maria Garcia', '{dueDate:d}')";
The fix
using var cmd = new SqlCommand(
"INSERT INTO dbo.Invoices (CustomerName, DueDate) VALUES (@name, @dueDate)", conn);
cmd.Parameters.Add("@name", SqlDbType.NVarChar, 100).Value = "Maria Garcia";
cmd.Parameters.Add("@dueDate", SqlDbType.Date).Value = dueDate;
Same culture, same date, and the insert went through (OK (1 row(s) affected)): the
parameter travels as a date value, so no text is ever parsed. In SQL scripts, the ISO form worked
under both languages:
PS> .\FixLab.exe 'Server=(localdb)\MSSQLLocalDB;Database=fix7_lab;Integrated Security=true' "INSERT INTO dbo.Invoices (CustomerName, DueDate) VALUES ('David Chen', '2026-10-31'); SET LANGUAGE British; INSERT INTO dbo.Invoices (CustomerName, DueDate) VALUES ('Aiko Tanaka', '2026-10-31'); SELECT Id, CustomerName, DueDate FROM dbo.Invoices ORDER BY Id"
info: Changed language setting to British.
3 | Maria Garcia | 2026-10-31
5 | David Chen | 2026-10-31
6 | Aiko Tanaka | 2026-10-31
OK (2 row(s) affected) in 0.3 s
One trap remains: the dashed form is safe for date and datetime2, not for
the old datetime. Under British, CAST('2026-10-31' AS datetime) failed with
error 242, "The conversion of a varchar data type to a datetime data type resulted in an out-of-range
value", while '20261031' and '2026-10-31T00:00:00' converted fine.
To find the bad rows in imported text, TRY_CONVERT returns NULL instead of failing,
and style 103 reads day-first explicitly:
PS> .\FixLab.exe 'Server=(localdb)\MSSQLLocalDB;Database=fix7_lab;Integrated Security=true' "CREATE TABLE dbo.InvoiceImport (CustomerName NVARCHAR(100) NOT NULL, DueDateText VARCHAR(20) NOT NULL); INSERT INTO dbo.InvoiceImport VALUES ('Sofia Rossi', '2026-10-31'), ('Kwame Mensah', '31/10/2026'), ('Lena Novak', '30/02/2026'); SELECT CustomerName, DueDateText, TRY_CONVERT(date, DueDateText) AS AsDefault, TRY_CONVERT(date, DueDateText, 103) AS AsStyle103 FROM dbo.InvoiceImport"
Sofia Rossi | 2026-10-31 | 2026-10-31 | NULL
Kwame Mensah | 31/10/2026 | NULL | 2026-10-31
Lena Novak | 30/02/2026 | NULL | NULL
A row that is NULL in both columns, like 30 February, is not a date in any order.
How it was reproduced
A console app from dotnet new console -n FixLab -f net10.0 (.NET SDK 10.0.403) with
Microsoft.Data.SqlClient 7.1.1, against SQL Server 2022 LocalDB 16.0.1210.3 with a Windows login
whose default language is us_english. The table dbo.Invoices has a
DATE column. Ids 1, 2 and 4 are missing above because failed inserts still use identity
values.
Frequently asked
- Which date format is always safe in SQL Server?
- In this test 2026-10-31 worked for date and datetime2 under both us_english and British, but failed for datetime under British. 20261031 and 2026-10-31T00:00:00 converted to datetime under British too, so use those for datetime.
- Why does the same date insert work on one SQL Server and fail on another?
- Text dates are read in the session's date order, which comes from the login's default language. A us_english session reads month first, a British one day first.
- How do I find rows with invalid dates in a varchar column?
- Select the rows where TRY_CONVERT(date, column) IS NULL. Add a style such as 103 for day-first text to tell a wrong order from a date that does not exist.
The same family of error for numbers is error 245, varchar to int. More decoded errors in the Fixes category.