ORA-01843: Not a Valid Month — Causes, Fixes, and Prevention
ORA-01843 is one of the most common date-related errors in Oracle databases, occurring when the database cannot interpret a month value during an implicit or explicit date conversion. This typically happens when the month portion of a date string falls outside the valid range (1–12), contains an unrecognizable string, or when the date format mask doesn't match the input string. If left unaddressed, this error can silently break batch jobs, ETL pipelines, and application insert/update operations.
Top 3 Causes
Cause 1: NLS_DATE_FORMAT Mismatch (Implicit Conversion Failure)
When Oracle tries to implicitly convert a string to a DATE using the session's NLS_DATE_FORMAT, any mismatch between the format and the actual string will trigger ORA-01843.
-- Check current session NLS_DATE_FORMAT
SELECT VALUE
FROM NLS_SESSION_PARAMETERS
WHERE PARAMETER = 'NLS_DATE_FORMAT';
-- This fails if NLS_DATE_FORMAT is 'DD-MON-RR' but input is 'YYYY-MM-DD'
-- ORA-01843: not a valid month
INSERT INTO orders (order_date) VALUES ('2024-07-15');
-- Fix: Set NLS explicitly at session level
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD';
INSERT INTO orders (order_date) VALUES ('2024-07-15'); -- Now works
Cause 2: Invalid Month Value in Input Data
Month values outside the range 1–12 — such as 0, 13, or garbled strings — will always raise ORA-01843. This is especially common during data migrations or integrations with legacy systems.
-- This will raise ORA-01843 (month = 13)
SELECT TO_DATE('2024-13-01', 'YYYY-MM-DD') FROM DUAL;
-- Detect bad month values in a staging table
SELECT raw_date_col
FROM staging_table
WHERE NOT REGEXP_LIKE(raw_date_col,
'^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$');
-- Safe insert using CASE to filter bad data
INSERT INTO target_table (id, reg_date)
SELECT id,
CASE
WHEN REGEXP_LIKE(raw_date_col,
'^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$')
THEN TO_DATE(raw_date_col, 'YYYY-MM-DD')
ELSE NULL
END
FROM staging_table;
Cause 3: Missing or Incorrect Format Mask in TO_DATE()
Calling TO_DATE() without an explicit format mask forces Oracle to rely on NLS_DATE_FORMAT. If the format doesn't align, the parser misreads the month position and throws ORA-01843.
-- BAD: No format mask — depends on NLS_DATE_FORMAT
SELECT TO_DATE('2024-07-15') FROM DUAL; -- May fail
-- GOOD: Always specify the format mask explicitly
SELECT TO_DATE('2024-07-15', 'YYYY-MM-DD') FROM DUAL;
SELECT TO_DATE('15/07/2024', 'DD/MM/YYYY') FROM DUAL;
SELECT TO_DATE('20240715', 'YYYYMMDD') FROM DUAL;
-- Oracle 12c+: Handle conversion errors gracefully
SELECT TO_DATE('2024-13-01' DEFAULT NULL ON CONVERSION ERROR,
'YYYY-MM-DD') AS safe_date
FROM DUAL;
-- Result: NULL (no exception raised)
Quick Fix Solutions
-- 1. Identify the problematic rows before bulk operations
SELECT raw_date_col
FROM staging_table
WHERE REGEXP_LIKE(raw_date_col, '^\d{4}-\d{2}-\d{2}$')
AND TO_NUMBER(SUBSTR(raw_date_col, 6, 2)) NOT BETWEEN 1 AND 12;
-- 2. Create a reusable safe conversion function
CREATE OR REPLACE FUNCTION safe_to_date(
p_str IN VARCHAR2,
p_fmt IN VARCHAR2 DEFAULT 'YYYY-MM-DD'
) RETURN DATE IS
BEGIN
RETURN TO_DATE(p_str, p_fmt);
EXCEPTION
WHEN OTHERS THEN RETURN NULL;
END;
/
-- Usage
SELECT safe_to_date('2024-13-01') AS bad_date, -- returns NULL
safe_to_date('2024-07-15') AS good_date -- returns 2024-07-15
FROM DUAL;
-- 3. Set consistent NLS on every session via logon trigger (DBA required)
CREATE OR REPLACE TRIGGER set_nls_on_logon
AFTER LOGON ON DATABASE
BEGIN
EXECUTE IMMEDIATE
'ALTER SESSION SET NLS_DATE_FORMAT=''YYYY-MM-DD''';
END;
/
Prevention Tips
Always use explicit format masks. Never rely on implicit date conversion or NLS_DATE_FORMAT defaults. Every TO_DATE() and TO_TIMESTAMP() call in your codebase should include a hardcoded format mask. Enforce this through code review checklists or static analysis tools.
Validate date data at the boundary. Before any bulk insert or migration, run a regex-based pre-check to identify rows with invalid month values. If you must store dates as VARCHAR2 in a legacy schema, add a BEFORE INSERT OR UPDATE trigger that calls TO_DATE() and raises a meaningful application error on failure. Preferably, always store date values in proper DATE or TIMESTAMP columns.
Related Oracle Errors
| Error Code | Description |
|---|---|
| ORA-01861 | Literal does not match format string |
| ORA-01847 | Day of month must be between 1 and 31 |
| ORA-01841 | Year must be between -4713 and 9999 |
| ORA-01858 | Non-numeric character found where numeric expected |
| ORA-01840 | Input value not long enough for date format |
📖 Want a more detailed guide?
Check out the full in-depth version (Korean) on oraerror.com — includes detailed analysis, additional SQL examples, and prevention tips.
Top comments (0)