{"record":{"id":"7a66a54435912eb6","repo":"n8n-io/n8n","slug":"value-is-not-a-valid-date","errorCode":null,"errorMessage":"Value is not a valid date","messagePattern":"Value is not a valid date","errorType":"exception","errorClass":"ExpressionExtensionError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/expression-runtime/src/extensions/string-extensions.ts","lineNumber":84,"sourceCode":"\tconst httpDate = DateTime.fromHTTP(dateString, { zone: defaultZone, setZone: true });\n\tif (httpDate.isValid) {\n\t\treturn httpDate;\n\t}\n\tconst rfc2822Date = DateTime.fromRFC2822(dateString, { zone: defaultZone, setZone: true });\n\tif (rfc2822Date.isValid) {\n\t\treturn rfc2822Date;\n\t}\n\tconst sqlDate = DateTime.fromSQL(dateString, { zone: defaultZone, setZone: true });\n\tif (sqlDate.isValid) {\n\t\treturn sqlDate;\n\t}\n\n\tconst parsedDateTime = DateTime.fromMillis(Date.parse(dateString), { zone: defaultZone });\n\tif (parsedDateTime.isValid) {\n\t\treturn parsedDateTime;\n\t}\n\n\tthrow new ExpressionExtensionError('Value is not a valid date');\n}\n\nfunction hash(value: string, extraArgs: string[]): string {\n\tconst algorithm = extraArgs[0]?.toLowerCase() ?? 'md5';\n\tswitch (algorithm) {\n\t\tcase 'base64':\n\t\t\treturn toBase64(value);\n\t\tcase 'md5':\n\t\t\treturn MD5(value);\n\t\tcase 'sha1':\n\t\tcase 'sha224':\n\t\tcase 'sha256':\n\t\tcase 'sha384':\n\t\tcase 'sha512':\n\t\tcase 'sha3':\n\t\t\tconst variant = (\n\t\t\t\t{\n\t\t\t\t\tsha1: 'SHA-1',","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/expression-runtime/src/extensions/string-extensions.ts#L66-L102","documentation":"The STRING `.toDateTime()` tries several parsers in turn — RFC2822, SQL, `DateTime.fromMillis(Date.parse(...))` — and if NONE yields a valid Luxon DateTime it throws 'Value is not a valid date'. This is the terminal failure after all auto-detection paths are exhausted.","triggerScenarios":"`.toDateTime()` on `'hello'`, `''`, `'2024-13-99'`, or any string none of the parsers accept.","commonSituations":"Empty field; wrong locale/format from an upstream system; free-text content in a field expected to hold a date.","solutions":["Validate the string parses as a date before the expression runs (e.g. `!isNaN(Date.parse(x))`).","If the format is known, pass it explicitly to a Luxon `fromFormat` call in a Code node.","Provide a fallback with `.ifEmpty()` / conditional logic upstream so empty strings never reach `.toDateTime()`."],"exampleFix":"// before\n{{ $json.raw.toDateTime() }}\n// after (guard in a Code node, then call the extension only when parseable)","handlingStrategy":"try-catch","validationCode":"const s = $json.raw;\nif (typeof s !== 'string' || !isNaN(Date.parse(s)) === false) {\n  // route to a default branch instead of letting .toDateTime() throw\n  $json.__dateValid = false;\n} else {\n  $json.__dateValid = true;\n}\nreturn $json;","typeGuard":"const isParsableDate = (s: string): boolean => !isNaN(Date.parse(s));","tryCatchPattern":"// Wrap expression evaluation (or use an Error Trigger / Set node fallback):\ntry {\n  return $json.raw.toDateTime().toISO();\n} catch {\n  return null; // or route the item to a quarantine branch\n}","preventionTips":["Pre-validate date strings with `Date.parse` in a Code node.","Provide a default for empty fields so they never reach `.toDateTime()`.","Use Luxon `fromFormat` in a Code node when the format is known but non-standard."],"tags":["expression","string","date","parsing","data-quality"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}