{"record":{"id":"ad6377761cf8f0c6","repo":"laurent22/joplin","slug":"invalid-date-s","errorCode":null,"errorMessage":"Invalid date: ${s}","messagePattern":"Invalid date: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/lib/import-enex.ts","lineNumber":37,"sourceCode":"import type * as FsExtra from 'fs-extra';\n\nlet fs_: typeof FsExtra = null;\nconst fs = () => {\n\tfs_ ??= shim.requireDynamic('fs-extra');\n\treturn fs_;\n};\n\nfunction dateToTimestamp(s: string, defaultValue: number = null): number {\n\t// Most dates seem to be in this format\n\tlet m = moment(s, 'YYYYMMDDTHHmmssZ');\n\n\t// But sometimes they might be in this format eg. 20180306T91108 AMZ\n\t// https://github.com/laurent22/joplin/issues/557\n\tif (!m.isValid()) m = moment(s, 'YYYYMMDDThmmss AZ');\n\n\tif (!m.isValid()) {\n\t\tif (defaultValue !== null) return defaultValue;\n\t\tthrow new Error(`Invalid date: ${s}`);\n\t}\n\n\treturn m.toDate().getTime();\n}\n\nfunction extractRecognitionObjId(recognitionXml: string) {\n\tconst r = recognitionXml.match(/objID=\"(.*?)\"/);\n\treturn r && r.length >= 2 ? r[1] : null;\n}\n\nasync function decodeBase64File(sourceFilePath: string, destFilePath: string) {\n\t// When something goes wrong with streams you can get an error \"EBADF, Bad file descriptor\"\n\t// with no strack trace to tell where the error happened.\n\n\t// Also note that this code is not great because there's a source and a destination stream\n\t// and while one stream might end, the other might throw an error or vice-versa. However\n\t// we can only throw one error from a promise. So before one stream\n\t// could end with resolve(), then another stream would get an error and call reject(), which","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/lib/import-enex.ts#L19-L55","documentation":"Thrown by dateToTimestamp() in the Evernote ENEX importer. It tries two moment formats (YYYYMMDDTHHmmssZ and YYYYMMDDThmmss AZ) to cover common Evernote date variants; if neither parses and no defaultValue was supplied, it throws rather than emit a garbage timestamp.","triggerScenarios":"Importing an .enex whose <created>/<updated> element contains a date string neither moment format recognizes — e.g. an unusual locale format, a malformed export, or a third-party tool that wrote non-standard dates.","commonSituations":"Evernote export produced by a non-official tool; regional date format in the ENEX; truncated/garbled export; very old Evernote format predating the standard; an ENEX hand-edited by the user.","solutions":["Pass a defaultValue to dateToTimestamp() so unparseable dates fall back to a sane timestamp instead of throwing.","Re-export from Evernote using the official client to get standard date formats.","Pre-process the ENEX XML to normalize date elements into YYYYMMDDTHHmmssZ before import.","If editing source, add another moment format string covering the observed variant."],"exampleFix":"// before\nconst ts = dateToTimestamp(s);\n// after - supply a default so import continues\ndateToTimestamp.timestamp = dateToTimestamp(s, Date.now());\n// or in the importer call site:\nconst ts = dateToTimestamp(s, time.unixMs());","handlingStrategy":"fallback","validationCode":"// Pass a default so unparseable dates degrade instead of throwing.\nconst ts = dateToTimestamp(enexDate, time.unixMs());","typeGuard":"function isParsableEnexDate(s: string): boolean {\n  if (!s) return false;\n  return require('moment')(s, ['YYYYMMDDTHHmmssZ', 'YYYYMMDDThmmss AZ'], true).isValid();\n}","tryCatchPattern":"let ts;\ntry {\n  ts = dateToTimestamp(s);\n} catch (e) {\n  if (/Invalid date:/.test(e.message)) {\n    logger.warn('Unparseable ENEX date, using now:', s);\n    ts = time.unixMs();\n  } else throw e;\n}","preventionTips":["Pass a defaultValue to dateToTimestamp when importing untrusted ENEX files.","Re-export from the official Evernote client for standard date formats.","Normalize ENEX date elements to YYYYMMDDTHHmmssZ before import.","Extend the parser with additional moment formats if you control the importer."],"tags":["import","enex","evernote","date-parsing"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}