{"record":{"id":"bae019e64ccb4714","repo":"laurent22/joplin","slug":"invalid-date-lastmodifiedstring","errorCode":null,"errorMessage":"Invalid date: ${lastModifiedString}","messagePattern":"Invalid date: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/lib/file-api-driver-webdav.js","lineNumber":79,"sourceCode":"\t\t}\n\n\t\tlet lastModifiedString = null;\n\n\t\ttry {\n\t\t\tlastModifiedString = this.api().resourcePropByName(resource, 'string', 'd:getlastmodified');\n\t\t} catch (error) {\n\t\t\tif (error.code === 'stringNotFound') {\n\t\t\t\t// OK - the logic to handle this is below\n\t\t\t} else {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\t// Note: Not all WebDAV servers return a getlastmodified date (eg. Seafile, which doesn't return the\n\t\t// property for folders) so we can only throw an error if it's a file.\n\t\tif (!lastModifiedString && !isDir) throw new Error(`Could not get lastModified date for resource: ${JSON.stringify(resource)}`);\n\t\tconst lastModifiedDate = lastModifiedString ? new Date(lastModifiedString) : new Date();\n\t\tif (isNaN(lastModifiedDate.getTime())) throw new Error(`Invalid date: ${lastModifiedString}`);\n\n\t\treturn {\n\t\t\tpath: path,\n\t\t\tupdated_time: lastModifiedDate.getTime(),\n\t\t\tisDir: isDir,\n\t\t};\n\t}\n\n\tasync setTimestamp() {\n\t\tthrow new Error('Not implemented'); // Not needed anymore\n\t}\n\n\tasync delta(path, options) {\n\t\tconst getDirStats = async path => {\n\t\t\tconst result = await this.list(path, { includeDirs: false });\n\t\t\treturn result.items;\n\t\t};\n","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/lib/file-api-driver-webdav.js#L61-L97","documentation":"Thrown by statFromResource_() right after parsing lastModifiedString with new Date(). If the resulting date is invalid (NaN), the server returned a getlastmodified value that isn't a parseable RFC1123 date, so the driver refuses to use a garbage timestamp for sync decisions.","triggerScenarios":"stat()/list() on a WebDAV server whose getlastmodified value is malformed — e.g. a non-English locale date string, a numeric epoch, or a custom format the Date constructor can't parse.","commonSituations":"WebDAV server localized to a non-standard date format; server returning epoch numbers instead of RFC1123; proxy/gateway mangling header values; rare server bug emitting empty/garbage strings that survived the earlier non-empty check.","solutions":["Inspect lastModifiedString in the message and normalize server-side to RFC1123 (e.g. configure Apache/nginx locale to C/en).","If the server emits epoch or ISO, extend the parser to detect and convert those formats before new Date().","Switch to a standards-compliant WebDAV server.","As a last resort, patch the driver to fall back to current time and log a warning."],"exampleFix":"// before\nconst lastModifiedDate = lastModifiedString ? new Date(lastModifiedString) : new Date();\nif (isNaN(lastModifiedDate.getTime())) throw new Error(`Invalid date: ${lastModifiedString}`);\n// after - try a couple of known formats, then degrade\nconst tryParse = (s) => {\n  const d = new Date(s);\n  if (!isNaN(d.getTime())) return d;\n  const epoch = Number(s); return isNaN(epoch) ? null : new Date(epoch);\n};\nconst lastModifiedDate = tryParse(lastModifiedString) ?? new Date();\nif (!tryParse(lastModifiedString)) logger.warn('Unparsable WebDAV date:', lastModifiedString);","handlingStrategy":"fallback","validationCode":"// Normalize the date string before relying on new Date().\nfunction safeDate(s: string): Date | null {\n  if (!s) return null;\n  const d = new Date(s);\n  if (!isNaN(d.getTime())) return d;\n  const epoch = Number(s);\n  return Number.isFinite(epoch) ? new Date(epoch) : null;\n}","typeGuard":"function isParsableDate(s: string): boolean {\n  if (!s) return false;\n  if (!isNaN(new Date(s).getTime())) return true;\n  return Number.isFinite(Number(s));\n}","tryCatchPattern":"try {\n  return await driver.stat(path);\n} catch (e) {\n  if (/Invalid date:/.test(e.message)) {\n    logger.warn('WebDAV returned unparseable date; using current time for', path);\n    return { path, updated_time: Date.now(), isDir: false };\n  }\n  throw e;\n}","preventionTips":["Configure the WebDAV server locale to C/en so dates are RFC1123.","Avoid proxies/gateways that mangle getlastmodified values.","Extend the parser to handle epoch/ISO if your server emits them.","Prefer standards-compliant WebDAV servers."],"tags":["webdav","sync","date-parsing","timestamp"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}