laurent22/joplin · warning · Error

has_more support not implemented

Error message

has_more support not implemented

What it means

Thrown by clearRoot() on the Joplin Server driver after deleting all listed items and clearing key values. If the initial list() returned hasMore === true, the driver has no pagination support in this debug/clear path and aborts rather than silently leaving items behind. It guards an incomplete implementation against partial cleanup.

Source

Thrown at packages/lib/file-api-driver-joplinServer.ts:307

	public async releaseLock(type: LockType, clientType: LockClientType, clientId: string) {
		await this.api().exec('DELETE', `api/locks/${type}_${clientType}_${clientId}`);
	}

	public async listLocks() {
		return this.api().exec('GET', 'api/locks');
	}

	public async clearRoot(path: string) {
		const response = await this.list(path);

		for (const item of response.items) {
			await this.delete(item.path);
		}

		await this.api().exec('POST', 'api/debug', null, { action: 'clearKeyValues' });

		if (response.hasMore) throw new Error('has_more support not implemented');
	}
}

View on GitHub (pinned to 2654b33620)

Solutions

  1. Paginate: call list() in a loop following context.nextLink until hasMore is false, deleting items each pass, before the clearKeyValues call.
  2. Reduce the number of items in the target below one page before clearing.
  3. Use the server-side clearKeyValues debug action alone if full deletion isn't required.
  4. Implement has_more handling in the driver's clearRoot as a proper fix.

Example fix

// before
public async clearRoot(path: string) {
  const response = await this.list(path);
  for (const item of response.items) await this.delete(item.path);
  await this.api().exec('POST', 'api/debug', null, { action: 'clearKeyValues' });
  if (response.hasMore) throw new Error('has_more support not implemented');
}
// after - drain pages first
public async clearRoot(path: string) {
  let ctx: any = null;
  do {
    const response = await this.list(path, { context: ctx });
    for (const item of response.items) await this.delete(item.path);
    ctx = response.context;
  } while (response.hasMore);
  await this.api().exec('POST', 'api/debug', null, { action: 'clearKeyValues' });
}
Defensive patterns

Strategy: validation

Validate before calling

// Don't call clearRoot on huge targets; or paginate yourself first.
const preview = await driver.list(path);
if (preview.hasMore) throw new Error('Clear root needs pagination; implement or shrink target.');

Type guard

function isHasMoreNotImplemented(e: any): boolean {
  return e && typeof e.message === 'string' && e.message.includes('has_more support not implemented');
}

Try / catch

try {
  await driver.clearRoot(path);
} catch (e) {
  if (isHasMoreNotImplemented(e)) {
    // drain pages manually, then retry clearRoot
    let ctx = null;
    do { const r = await driver.list(path, { context: ctx }); for (const it of r.items) await driver.delete(it.path); ctx = r.context; } while (r.hasMore);
    await driver.api().exec('POST', 'api/debug', null, { action: 'clearKeyValues' });
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling clearRoot() (used by sync reset / debug wipe) on a Joplin Server target that contains more items than fit in a single list response page.

Common situations: Running a sync debug/reset on a large Joplin Server account; CI test fixtures that over-populate the root; a real account with many items where the dev intentionally wipes the target.

Related errors


AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12). Data as JSON: /api/errors/ab47ce4bf44e6992. Report an issue: GitHub.