Zie619/n8n-workflows · warning · Error
Failed to convert start time. Reason: ${startDtTargetZone.in
Error message
Failed to convert start time. Reason: ${startDtTargetZone.invalidReason || 'Unknown'} What it means
Produced in 'Convert time to CST America / Chicago' when Luxon's DateTime.fromISO(starttime, {zone:'utc'}).setZone(timeZone) yields an invalid DateTime (isValid false, e.g. invalidReason 'bad input format' or 'unsupported zone'). Important: this throw is INSIDE the node's try/catch, which catches it and writes item.json.conversionError = error.message — so it does not fail the workflow; the message surfaces as a per-item error flag consumed downstream.
Source
Thrown at workflows/Webhook/0829_Webhook_Code_Create_Webhook.json:1251
"type": "string",
"value": "={{ $json.body.message.call.customer.number }}"
}
]
}
},
"typeVersion": 3.3,
"notes": "This set node performs automated tasks as part of the workflow."
},
{
"id": "b4bc5cee-d631-4aa8-a3ff-59a0b647d36a",
"name": "Convert time to CST America / Chicago",
"type": "n8n-nodes-base.code",
"position": [
1480,
1580
],
"parameters": {
"jsCode": "// Get all input items\nconst items = $input.all();\n\n// Loop through each item\nfor (const item of items) {\n // Get the values from the current item's JSON data\n const startTimeUTC = item.json.starttime;\n const endTimeUTC = item.json.endtime;\n const targetTimeZone = item.json.timeZone; // e.g., \"America/Chicago\"\n\n // Basic validation: ensure the necessary fields exist\n if (!startTimeUTC || !endTimeUTC || !targetTimeZone) {\n console.warn(`Skipping item due to missing time data or timezone. Item JSON: ${JSON.stringify(item.json)}`);\n item.json.conversionError = \"Missing starttime, endtime, or timeZone\";\n continue; // Move to the next item\n }\n\n try {\n // --- Start Time Conversion ---\n // Parse the original UTC ISO string using Luxon (NO $ prefix)\n const startDt = luxon.DateTime.fromISO(startTimeUTC, { zone: 'utc' });\n\n // Convert the DateTime object to the target timezone\n const startDtTargetZone = startDt.setZone(targetTimeZone);\n\n // Check if the conversion was valid\n if (!startDtTargetZone.isValid) {\n throw new Error(`Failed to convert start time. Reason: ${startDtTargetZone.invalidReason || 'Unknown'}`);\n }\n\n // Format the result back into an ISO string with the correct offset\n item.json.starttime = startDtTargetZone.toISO();\n\n // --- End Time Conversion ---\n // Parse the original UTC ISO string using Luxon (NO $ prefix)\n const endDt = luxon.DateTime.fromISO(endTimeUTC, { zone: 'utc' });\n\n // Convert the DateTime object to the target timezone\n const endDtTargetZone = endDt.setZone(targetTimeZone);\n\n // Check if the conversion was valid\n if (!endDtTargetZone.isValid) {\n throw new Error(`Failed to convert end time. Reason: ${endDtTargetZone.invalidReason || 'Unknown'}`);\n }\n\n // Format the result back into an ISO string with the correct offset\n item.json.endtime = endDtTargetZone.toISO();\n\n // Optionally remove the error flag if conversion was successful this time\n delete item.json.conversionError;\n\n } catch (error) {\n console.error(`Error converting time for item: ${JSON.stringify(item.json)}. Error: ${error.message}`);\n // Add/update the error flag to the item's JSON\n item.json.conversionError = error.message;\n }\n}\n// Return the modified array of items\nreturn items;"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "2c8b2884-14d3-4bd4-92d8-6e402ca3a8de",
"name": "Create Event",
"type": "n8n-nodes-base.googleCalendar",
"onError": "continueErrorOutput",
"position": [
1700,
1580
],
"parameters": {
"end": "={{ $json.endtime }}",
"start": "={{ $json.starttime }}",
"calendar": {
"__rl": true,View on GitHub (pinned to 94007c1445)
Solutions
- Log conversionError items: their message names the Luxon invalidReason; fix the source to emit full ISO 8601 UTC strings (e.g., 2024-03-01T14:00:00Z).
- Normalize before parsing: if starttime is a number, treat it as epoch ms (DateTime.fromMillis); if it lacks zone info, append 'Z' or use {zone:'utc'} deliberately.
- Validate timeZone against a known IANA list or intercept common aliases (CST->America/Chicago) before setZone.
- Add a Filter/IF after this node to route conversionError items to a review path instead of letting them reach Google Calendar.
Example fix
// before
const startDt = luxon.DateTime.fromISO(startTimeUTC, { zone: 'utc' });
const startDtTargetZone = startDt.setZone(targetTimeZone);
if (!startDtTargetZone.isValid) {
throw new Error(`Failed to convert start time. Reason: ${startDtTargetZone.invalidReason || 'Unknown'}`);
}
// after - normalize common inputs first
const zoneAliases = { CST: 'America/Chicago', CDT: 'America/Chicago', EST: 'America/New York' };
const tz = zoneAliases[targetTimeZone] || targetTimeZone.trim();
let startDt = luxon.DateTime.fromISO(String(startTimeUTC), { zone: 'utc' });
if (!startDt.isValid && typeof startTimeUTC === 'number') {
startDt = luxon.DateTime.fromMillis(startTimeUTC);
}
const startDtTargetZone = startDt.setZone(tz);
if (!startDtTargetZone.isValid) {
item.json.conversionError = `Failed to convert start time (${startTimeUTC}) to ${tz}: ${startDtTargetZone.invalidReason}`;
continue;
} Defensive patterns
Strategy: fallback
Validate before calling
const isValidIso = (s) => typeof s === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})$/.test(s);
const zoneAliases = { CST: 'America/Chicago', CDT: 'America/Chicago' };
const tz = zoneAliases[targetTimeZone] || String(targetTimeZone || '').trim();
if (!isValidIso(startTimeUTC) || !isValidIso(endTimeUTC)) {
item.json.conversionError = `Non-ISO datetime: start=${startTimeUTC}, end=${endTimeUTC}`;
continue;
} Type guard
const isIanaZone = (z) => typeof z === 'string' && /^(Africa|America|Antarctica|Asia|Atlantic|Australia|Europe|Indian|Pacific|Etc)\//.test(z) || z === 'UTC';
Try / catch
try {
item.json.starttime = luxon.DateTime.fromISO(startTimeUTC, { zone: 'utc' }).setZone(tz).toISO();
item.json.endtime = luxon.DateTime.fromISO(endTimeUTC, { zone: 'utc' }).setZone(tz).toISO();
delete item.json.conversionError;
} catch (e) {
item.json.conversionError = e.message; // per-item flag, workflow continues
} Prevention
- Require full ISO 8601 UTC strings from source systems; validate them at ingestion, not mid-workflow.
- Maintain an alias table for user-supplied zones (CST/EST) instead of passing them to setZone raw.
- Add a Filter after this node so conversionError items never reach the calendar-write node.
When it happens
Trigger: starttime/endtime not a valid ISO 8601 string (e.g., '2024-03-01 14:00' without seconds/zone, an epoch number, an Excel serial), or timeZone not a valid IANA name ('CST', 'America/ Chicago', empty). The earlier missing-fields check already flags absent values via conversionError + continue.
Common situations: Source systems emitting non-ISO datetimes (spreadsheets, legacy APIs), users typing 'CST'/'CDT' abbreviations instead of 'America/Chicago', or timezone strings with whitespace/typos. Downstream nodes must handle items carrying conversionError, otherwise 'Create Event' receives garbage times.
Related errors
- Approved quantity must be greater than 0
- ${fileName} → ${baseName} → Unrecognized file name structure
- The video ID parameter is empty.
- Invalid data structure
- Could not find video URL in the JSON data.
AI-assisted analysis of Zie619/n8n-workflows@94007c1445 (2026-08-15).
Data as JSON: /api/errors/4602457e9d9adad4.
Report an issue: GitHub.