Missing N prefix on NVARCHAR literals silently mangles Japanese/Korean text and emoji without any error
Published 2026-08-16 · Updated 2026-08-16 · Last Verified 2026-08-16
Answer
When a string literal is assigned directly to an NVARCHAR column in SQL Server without the `N` prefix, the literal is implicitly converted to the connection's default code page before being stored as NVARCHAR. Characters that cannot be represented in that code page — Japanese, Korean, emoji, and the like — are lost, but this raises no error or warning; the value simply corrupts silently. ASCII-only test data never reveals the problem, so it is often discovered only after going to production, and the same pattern tends to recur.
Applicability of This Document
| Product | SQL Server (affects Unicode string literals in general) |
|---|---|
| Verified Versions | SQL Server 2012 and later (including Azure SQL Database / Managed Instance) |
| Environment | On-premises, EC2, Amazon RDS for SQL Server, Azure SQL |
| Required Permissions | Diagnostic SQL only needs SELECT on the target table. Source-code search needs read access to the repository |
| Execution Impact | All diagnostics in this article are read-only. Fixing/recovering already-corrupted data separately requires an UPDATE on the affected rows |
| Restart | Not required |
| Last Verified | 2026-08-16 |
Ready-to-Run Commands
- 対象
- SQL Server 2012 and later / Azure SQL Database, Managed Instance
- 権限
- SELECT on the target table (metadata can be viewed with the public role)
- 変更作業
- None (read-only)
- Production実行
- Safe
-- 対象: SQL Server 2012 以降 / Azure SQL Database・Managed Instance
-- 権限: メタデータの参照はpublicロールで可。個々のデータ確認には対象テーブルのSELECT権限が必要
-- 変更作業: なし(参照のみ)
-- Production実行: 可能
-- 非ASCII文字を保持しうる nvarchar / nchar 列を一覧化する(調査対象の絞り込み用)
SELECT
t.name AS table_name,
c.name AS column_name,
ty.name AS type_name,
c.max_length
FROM sys.columns AS c
INNER JOIN sys.tables AS t
ON t.object_id = c.object_id
INNER JOIN sys.types AS ty
ON ty.user_type_id = c.user_type_id
WHERE ty.name IN ('nvarchar', 'nchar')
ORDER BY t.name, c.column_id;This list only narrows the scope of investigation — the mere existence of such a column is not itself a problem. The next step checks the actual data in each column.
- 対象
- The application / stored-procedure source-code repository
- 権限
- Read access to the repository
- 変更作業
- None (search only)
- Production実行
- Safe
# 対象: アプリケーション・ストアドプロシージャのソースコードリポジトリ
# 権限: リポジトリの読み取り権限
# 変更作業: なし(参照のみ)
# Production実行: 可能
#
# .sql ファイル内で、Nプレフィックスの無いシングルクォート文字列リテラルのうち
# 非ASCII文字を含むものを検出する(正規表現なので誤検知はあり、ヒット箇所は目視確認が前提)
grep -RnoP "(?<![Nn])'[^']*[^\x00-\x7F][^']*'" --include=*.sql .
# 文字列結合や sp_executesql で動的SQLを組み立てている箇所も洗い出す
grep -RniE "(sp_executesql|EXEC\(|exec\()" --include=*.sql --include=*.cs --include=*.ts .This also catches comments and intentional non-ASCII strings (such as error-message text), so every regex hit is a "candidate to investigate," not a "confirmed bug." Check each hit individually to see whether it is an assignment into an NVARCHAR column or parameter.
When to Use This
- Inserting data containing Japanese, Korean, or emoji raises no error, but the stored value shows "?" or different characters
- Application tests (which use ASCII-only test data) show no problem; the issue surfaces only after going to production or loading real data
- It only happens on write paths that go through dynamic SQL (string concatenation or sp_executesql)
- The same symptom recurs in a different place or a different project, even in a codebase that was supposedly already "fixed"
Possible Causes (Most Likely First)
01
The string literal is implicitly converted to the connection's default code page
A single-quoted string literal without the N prefix is first interpreted as a non-Unicode string, then converted to the connection's default code page before being assigned to the NVARCHAR type. Characters that cannot be represented in that code page are lost during the conversion.
02
Dynamic SQL is assembled by string concatenation without thinking about NVARCHAR
When building SQL statements via string concatenation or sp_executesql, it is easy to forget the N prefix on the literal being embedded — especially when the value is embedded directly as a string rather than passed as a parameter.
03
No error or warning is raised, so tests rarely catch it
Because neither a compile-time nor a runtime error occurs, ASCII-only test data looks perfectly fine. The symptom appears only once real non-ASCII data is written.
04
Once a character is lost, it cannot be recovered without an independent source
A character lost to implicit conversion no longer exists anywhere inside the NVARCHAR column. Unless there is some independent source — logs in another system, a copy of the original data — the correct value can never be restored afterward.
Diagnostic Steps
- 1
Enumerate the nvarchar/nchar columns on the target table
Read-onlyUse the diagnostic SQL above to list columns that could hold non-ASCII characters.
- 2
Search the source code for missing N prefixes
Read-onlyUse grep to find suspicious string literals and places that build dynamic SQL, then check each one individually.
- 3
Check existing data for signs of corruption
Read-onlyFor columns that should hold non-ASCII text, individually check whether values have been replaced by unintended characters.
- 4
Check whether an independent source exists for the corrupted data
Read-onlyCheck whether some other source of truth — an external system's logs, a record from a different path — still holds the correct values.
Solutions
Low-risk action that can be done immediately
Add the N prefix to every NVARCHAR literal in new code
LowStart with newly added or modified SQL code, and add the N prefix to existing non-ASCII string literals as well.
Fix the places that build dynamic SQL first
LowParts that assemble SQL via string concatenation or sp_executesql have the widest blast radius, so fix them first. Switch to parameterization where possible.
Change requiring advance review
Add it as a code-review checklist item
LowDocument, as an explicit review item, that string literals assigned to NVARCHAR columns must be checked.
Mechanically detect missing N prefixes in CI / pre-commit
MediumWire the grep pattern above into CI or a pre-commit hook, so detection does not depend solely on manual review.
Work requiring expert review
Consider recovering already-corrupted existing data
Expert Review RequiredRecovery is only possible if an independent source exists (external logs, a backup taken through a different path, etc.). If none exists, state clearly to stakeholders that recovery is impossible, and focus effort on preventing recurrence going forward.
!Warnings
- Adding the N prefix to new code does not automatically fix existing data that was already corrupted and stored.
- If the application layer builds SQL strings itself, using parameterized binding instead of string concatenation avoids this problem entirely. Prefer parameterization wherever possible.
- If test data is ASCII-only, the issue will not surface until production. Deliberately include non-ASCII characters (Japanese, Korean, emoji, etc.) in tests.
- Even after a full sweep fix, the old pattern can creep back in through a new code path or a sample SQL snippet pulled in from elsewhere. Keep the automated detection running continuously.
Differences by Version and Environment
If This Doesn't Resolve It
Did you search across the whole codebase for the same pattern, not just one spot?
Fixing a single location does not rule out the same pattern existing in other stored procedures or batch jobs.
For columns suspected of corruption, does an independent source still exist?
If not, design future operations on the assumption that recovery is impossible.
Write paths that use parameterized queries are not affected by this issue in the first place
Confirm that paths using ORM or driver parameter binding are out of scope, so you prioritize correctly.
Basis and Limitations of This Document
Explanation based on official product documentation
That Unicode string literals require the N prefix is a specification explicitly documented by Microsoft for SQL Server. The "easy to miss" nature and tendency to recur described in this article are a generalization of patterns observed repeatedly across real operations, and do not include any specific customer's incident counts or dates.
FAQ
Does forgetting the N prefix always cause an error?
No. It causes neither a compile-time nor a runtime error. Characters that cannot be represented in the connection's default code page are silently lost, while the operation itself completes normally.
Does this also happen outside of dynamic SQL?
Yes. Any path that assigns a string literal directly into an NVARCHAR column, variable, or parameter is affected the same way, even in a plain static INSERT statement.
Does using parameterized queries prevent this?
Yes. Paths that use a driver or ORM's parameter binding have the value's type and character encoding handled correctly on the driver side, so this problem cannot occur at all.
Can corrupted data be recovered?
Only if an independent source still exists — such as logs from an external system or records captured through a different path. The original character no longer exists inside the NVARCHAR column itself, so without such a source it cannot be recovered.
Questions This Document Covers
- Why does Japanese or Korean text get mangled in SQL Server
- What happens with a SQL string that has no N prefix
What the Risk Labels Mean
- Read-onlyDoes not change data or settings.
- LowImpact is limited, but permissions and load should be checked.
- MediumMay affect performance, locking, or cost.
- HighMay cause an outage, data loss, or require recovery work.
- Expert Review RequiredRequires a separate review before applying to production.
GIIP's Scope of Support
GIIP has built a review-stage check that mechanically detects missing N prefixes for any newly added SQL code. Because the same class of incident has recurred, in different forms, across multiple projects, our policy is to never rely solely on manual review and to always pair it with automated detection.
Author & Technical Review
GIIP Production Operations Team
About 30 years of experience in designing, migrating, and operating large-scale web services, SQL Server, Oracle, AWS, and Azure. Experience includes 12 sets of x12large-class AWS RDS for SQL Server environments, an Oracle environment with roughly 120,000 tables, and migrating roughly 3TB from TiDB to Aurora MySQL. AI agents and human experts currently continue to monitor and operate multiple cloud databases and about 30 web services.
What to Check When Migrating from utf8mb3 to utf8mb4 in Aurora MySQL
The first thing that breaks when converting to utf8mb4 is index key length. This organizes the SQL for finding targets, how to choose a collation, the impact of conversion, and where the settings live.
ai-operationsA guard that detects contamination in AI-generated content, and an operating rule that never treats regeneration alone as "done"
This explains an operating guard that mechanically detects known contamination patterns in AI-generated content and never calls a regeneration "done" until someone has directly checked the resulting body text.
incident-responseWhat database incidents AI agents can handle, and what humans must decide
We split incident response into phases to separate what AI can own (detection, triage, limited initial response) from what requires human judgment (irreversible actions, shutdown decisions), and provide read-only triage queries.
Related Services
Request a sweep audit of NVARCHAR literals
If you need to repeat the same checks across multiple environments, we can discuss your entire operations setup.
Request a sweep audit of NVARCHAR literals