{"record":{"id":"92d233f1ab238a8d","repo":"n8n-io/n8n","slug":"cannot-convert-to-luxon-datetime","errorCode":null,"errorMessage":"cannot convert to Luxon DateTime","messagePattern":"cannot convert to Luxon DateTime","errorType":"exception","errorClass":"ExpressionExtensionError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/expression-runtime/src/extensions/string-extensions.ts","lineNumber":211,"sourceCode":"export function toDateTime(value: string, extraArgs: [string] = ['']): DateTime {\n\ttry {\n\t\tconst [valueFormat] = extraArgs;\n\n\t\tif (valueFormat) {\n\t\t\tif (\n\t\t\t\tvalueFormat === 'ms' ||\n\t\t\t\tvalueFormat === 's' ||\n\t\t\t\tvalueFormat === 'us' ||\n\t\t\t\tvalueFormat === 'excel'\n\t\t\t) {\n\t\t\t\treturn numberToDateTime(Number(value), [valueFormat]);\n\t\t\t}\n\t\t\treturn DateTime.fromFormat(value, valueFormat);\n\t\t}\n\n\t\treturn tryToParseDateTime(value);\n\t} catch (error) {\n\t\tthrow new ExpressionExtensionError('cannot convert to Luxon DateTime');\n\t}\n}\n\nfunction urlDecode(value: string, extraArgs: boolean[]): string {\n\tconst [entireString = false] = extraArgs;\n\tif (entireString) {\n\t\treturn decodeURI(value.toString());\n\t}\n\treturn decodeURIComponent(value.toString());\n}\n\nfunction urlEncode(value: string, extraArgs: boolean[]): string {\n\tconst [entireString = false] = extraArgs;\n\tif (entireString) {\n\t\treturn encodeURI(value.toString());\n\t}\n\treturn encodeURIComponent(value.toString());\n}","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/expression-runtime/src/extensions/string-extensions.ts#L193-L229","documentation":"A catch-all wrapper around the STRING `.toDateTime()` body. The outer `try`/`catch` re-throws any inner failure (unknown format string that is not `ms`/`s`/`us`/`excel` and not a valid Luxon token, an unparseable value with a custom format, or a throw from the number-conversion path) as the generic 'cannot convert to Luxon DateTime'. It obscures the underlying cause.","triggerScenarios":"Passing a format argument that is neither a numeric shortcut nor a valid Luxon format token (e.g. `.toDateTime('YYYY')` with wrong casing, or `.toDateTime('iso8601')`); or a value that cannot be parsed with the supplied format.","commonSituations":"Custom format string Luxon rejects; downstream of 335/337 when a format was supplied; year-first vs day-first locale confusion.","solutions":["Omit the format argument to use auto-detection, OR supply a valid Luxon format token (e.g. `'yyyy-MM-dd HH:mm:ss'`).","If the value is numeric, use the number `.toDateTime('ms'|'s'|'us'|'excel')` variant instead.","Pre-parse in a Code node with Luxon `DateTime.fromFormat` to surface the real error, then forward the DateTime."],"exampleFix":"// before\n{{ $json.stamp.toDateTime('YYYY-mm-dd') }}\n// after\n{{ $json.stamp.toDateTime('yyyy-MM-dd') }}","handlingStrategy":"try-catch","validationCode":"// Validate format token + parseability before the expression:\nconst luxon = require('luxon');\nconst dt = luxon.DateTime.fromFormat($json.stamp, $json.fmt || '');\nif (!dt.isValid) {\n  throw new Error(`cannot convert to Luxon DateTime: ${dt.invalidReason}`);\n}\nreturn $json;","typeGuard":"const isValidLuxonDateTime = (dt: { isValid: boolean }): boolean => dt.isValid;","tryCatchPattern":"try {\n  return $json.stamp.toDateTime($json.fmt).toISO();\n} catch {\n  // fall back to auto-detection or a quarantine branch\n  return $json.stamp.toDateTime().toISO();\n}","preventionTips":["Omit the format argument to use auto-detection, or pass a valid Luxon token.","Use the numeric `.toDateTime('ms'|'s'|'us'|'excel')` variant for epochs.","Pre-parse in a Code node with Luxon to surface the real reason."],"tags":["expression","string","date","format","parsing"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}