laurent22/joplin · error · Error
Invalid WebDAV resource format: ${JSON.stringify(resource)}
Error message
Invalid WebDAV resource format: ${JSON.stringify(resource)} What it means
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.
Source
Thrown at packages/lib/file-api-driver-webdav.js:44
}
async stat(path) {
try {
const result = await this.api().execPropFind(path, 0, ['d:getlastmodified', 'd:resourcetype']);
const resource = this.api().objectFromJson(result, ['d:multistatus', 'd:response', 0]);
return this.statFromResource_(resource, path);
} catch (error) {
if (error.code === 404) return null;
throw error;
}
}
statFromResource_(resource, path) {
// WebDAV implementations are always slightly different from one server to another but, at the minimum,
// a resource should have a propstat key - if not it's probably an error.
const propStat = this.api().arrayFromJson(resource, ['d:propstat']);
if (!Array.isArray(propStat)) throw new Error(`Invalid WebDAV resource format: ${JSON.stringify(resource)}`);
// Disabled for now to try to fix this: https://github.com/laurent22/joplin/issues/624
//
// const httpStatusLine = this.api().stringFromJson(resource, ['d:propstat',0,'d:status', 0]);
// if ( typeof httpStatusLine === 'string' && httpStatusLine.indexOf('404') >= 0 ) throw new JoplinError(resource, 404);
const resourceTypes = this.api().resourcePropByName(resource, 'array', 'd:resourcetype');
let isDir = false;
if (Array.isArray(resourceTypes)) {
for (let i = 0; i < resourceTypes.length; i++) {
const t = resourceTypes[i];
if (typeof t === 'object' && 'd:collection' in t) {
isDir = true;
break;
}
}
}
View on GitHub (pinned to 2654b33620)
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.
Example fix
// before
const propStat = this.api().arrayFromJson(resource, ['d:propstat']);
if (!Array.isArray(propStat)) throw new Error(`Invalid WebDAV resource format: ${JSON.stringify(resource)}`);
// after - fall back to alternate namespace and surface a clearer cause
let propStat = this.api().arrayFromJson(resource, ['d:propstat']) || this.api().arrayFromJson(resource, ['D:propstat']);
if (!Array.isArray(propStat)) throw new Error(`WebDAV resource missing propstat (check URL/auth): ${JSON.stringify(resource).slice(0, 200)}`); Defensive patterns
Strategy: validation
Validate before calling
// Probe the endpoint with a PROPFIND before syncing.
const r = await fetch(baseUrl, { method: 'PROPFIND', headers: { Depth: '0' } });
if (!r.ok || !(await r.text()).includes('propstat')) {
throw new Error('Configured URL is not a standards-compliant WebDAV endpoint.');
} Type guard
function hasValidPropStat(resource: any): boolean {
return !!resource && Array.isArray(resource?.['d:propstat'] ?? resource?.['D:propstat']);
} Try / catch
try {
return await driver.stat(path);
} catch (e) {
if (/Invalid WebDAV resource format/.test(e.message)) {
throw new Error('WebDAV server returned a malformed PROPFIND; check URL and credentials.');
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Could not get lastModified date for resource: ${JSON.stringi
- href ${href} not in baseUrl ${baseUrl} nor relativeBaseUrl $
- Cannot initialise synchroniser.
- WebDAV directory not found: ${options.path()}
- Invalid date: ${lastModifiedString}
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/80b8b7e95ca2bacb.
Report an issue: GitHub.