{"record":{"id":"80b8b7e95ca2bacb","repo":"laurent22/joplin","slug":"invalid-webdav-resource-format-json-stringify-r","errorCode":null,"errorMessage":"Invalid WebDAV resource format: ${JSON.stringify(resource)}","messagePattern":"Invalid WebDAV resource format: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/lib/file-api-driver-webdav.js","lineNumber":44,"sourceCode":"\t}\n\n\tasync stat(path) {\n\t\ttry {\n\t\t\tconst result = await this.api().execPropFind(path, 0, ['d:getlastmodified', 'd:resourcetype']);\n\n\t\t\tconst resource = this.api().objectFromJson(result, ['d:multistatus', 'd:response', 0]);\n\t\t\treturn this.statFromResource_(resource, path);\n\t\t} catch (error) {\n\t\t\tif (error.code === 404) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tstatFromResource_(resource, path) {\n\t\t// WebDAV implementations are always slightly different from one server to another but, at the minimum,\n\t\t// a resource should have a propstat key - if not it's probably an error.\n\t\tconst propStat = this.api().arrayFromJson(resource, ['d:propstat']);\n\t\tif (!Array.isArray(propStat)) throw new Error(`Invalid WebDAV resource format: ${JSON.stringify(resource)}`);\n\n\t\t// Disabled for now to try to fix this: https://github.com/laurent22/joplin/issues/624\n\t\t//\n\t\t// const httpStatusLine = this.api().stringFromJson(resource, ['d:propstat',0,'d:status', 0]);\n\t\t// if ( typeof httpStatusLine === 'string' && httpStatusLine.indexOf('404') >= 0 ) throw  new JoplinError(resource, 404);\n\n\t\tconst resourceTypes = this.api().resourcePropByName(resource, 'array', 'd:resourcetype');\n\t\tlet isDir = false;\n\t\tif (Array.isArray(resourceTypes)) {\n\t\t\tfor (let i = 0; i < resourceTypes.length; i++) {\n\t\t\t\tconst t = resourceTypes[i];\n\t\t\t\tif (typeof t === 'object' && 'd:collection' in t) {\n\t\t\t\t\tisDir = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/lib/file-api-driver-webdav.js#L26-L62","documentation":"Thrown by the WebDAV driver when parsing a PROPFIND response: statFromResource_() expects each d:response element to contain a d:propstat array. If the parsed resource lacks a recognizable propstat, the server returned a non-standard or malformed multi-status body, and the driver cannot extract type/timestamp info, so it aborts.","triggerScenarios":"Calling stat() on a WebDAV server whose PROPFIND reply omits propstat — e.g. server returns an error inside the response element, uses a different XML namespace prefix, or returns plain text/HTML instead of multistatus XML.","commonSituations":"Misconfigured WebDAV server (Nextcloud, Seafile, nginx, Apache) returning non-standard XML; wrong base URL pointing at a non-WebDAV endpoint; namespace prefix mismatch (d: vs D:); authentication failure returning an HTML login page parsed as a resource.","solutions":["Verify the WebDAV URL is correct and points at a real WebDAV endpoint (test with curl PROPFIND).","Check credentials — an HTML auth page is often mis-parsed as a resource; re-link with valid user/pass.","Confirm namespace handling — some servers use 'D:' not 'd:'; ensure the client lower-cases or maps prefixes.","Capture the raw PROPFIND response to see what the server actually sent and adapt the parser."],"exampleFix":"// before\nconst propStat = this.api().arrayFromJson(resource, ['d:propstat']);\nif (!Array.isArray(propStat)) throw new Error(`Invalid WebDAV resource format: ${JSON.stringify(resource)}`);\n// after - fall back to alternate namespace and surface a clearer cause\nlet propStat = this.api().arrayFromJson(resource, ['d:propstat']) || this.api().arrayFromJson(resource, ['D:propstat']);\nif (!Array.isArray(propStat)) throw new Error(`WebDAV resource missing propstat (check URL/auth): ${JSON.stringify(resource).slice(0, 200)}`);","handlingStrategy":"validation","validationCode":"// Probe the endpoint with a PROPFIND before syncing.\nconst r = await fetch(baseUrl, { method: 'PROPFIND', headers: { Depth: '0' } });\nif (!r.ok || !(await r.text()).includes('propstat')) {\n  throw new Error('Configured URL is not a standards-compliant WebDAV endpoint.');\n}","typeGuard":"function hasValidPropStat(resource: any): boolean {\n  return !!resource && Array.isArray(resource?.['d:propstat'] ?? resource?.['D:propstat']);\n}","tryCatchPattern":"try {\n  return await driver.stat(path);\n} catch (e) {\n  if (/Invalid WebDAV resource format/.test(e.message)) {\n    throw new Error('WebDAV server returned a malformed PROPFIND; check URL and credentials.');\n  }\n  throw e;\n}","preventionTips":["Validate the WebDAV URL with a PROPFIND probe before configuring sync.","Ensure credentials are correct so an HTML login page isn't mis-parsed.","Prefer Nextcloud/ownCloud or other standards-compliant servers.","Handle namespace prefix variants (d: vs D:) if supporting multiple servers."],"tags":["webdav","sync","propfind","parsing","config"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}