Skip to content

Fixes xbrowsersync/app#190#518

Open
Tahlor wants to merge 1 commit intoxbrowsersync:masterfrom
Tahlor:dev2
Open

Fixes xbrowsersync/app#190#518
Tahlor wants to merge 1 commit intoxbrowsersync:masterfrom
Tahlor:dev2

Conversation

@Tahlor
Copy link

@Tahlor Tahlor commented Nov 21, 2025

Problem

The extension fails with "Missing container: other bookmarks" error when the browser's native bookmark container IDs don't match the expected hardcoded values ('1' for toolbar, '2' for other bookmarks). This can occur in certain browser configurations or when the bookmark structure has been modified. See #190

Solution

Added resilient container detection with two fallback mechanisms:

  1. Position-based fallback in getNativeContainerIds(): When hardcoded IDs don't match, the code now attempts to identify containers by their position in the bookmark tree (toolbar at index 0, other bookmarks at index 1). This works reliably for Chromium browsers which typically have exactly 2 root children.

  2. Recovery fallback in clearNativeBookmarks(): If container IDs still can't be found, the code now traverses the bookmark tree to find xBrowserSync containers by their titles ([xbs] Other, [xbs] Toolbar, [xbs] Menu) and clears them directly. This ensures bookmarks can be reset even when the native container structure is unexpected.

Changes

  • Enhanced getNativeContainerIds() with position-based container detection fallback
  • Added clearNativeBookmarksFallback() method for recovery when container IDs are unavailable
  • Updated clearNativeBookmarks() to catch ContainerNotFoundError and attempt fallback recovery
  • Added defensive checks to ensure position-based fallback only runs when root has exactly 2 children

Testing

  • Verified sync works when container IDs don't match expected values
  • Confirmed fallback recovery successfully clears bookmarks in error scenarios
  • Tested on Edge (Chromium-based) where container ID was '467' instead of expected '2'

Notes

This is a defensive programming approach that makes the extension resilient to browser implementation variations without attempting to modify the browser's native bookmark structure (which we don't control).

@tomangert
Copy link

I had this problem and this patch fixed it. Thanks!

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves Chromium bookmark container handling to prevent sync failures when native bookmark root container IDs don’t match the previously hardcoded assumptions (reported in #190).

Changes:

  • Adds a position-based fallback in getNativeContainerIds() when hardcoded root IDs don’t resolve.
  • Adds a recovery path in clearNativeBookmarks() to attempt clearing xBrowserSync folders by title when container resolution fails.
  • Introduces clearNativeBookmarksFallback() to traverse the bookmark tree and remove items found under [xbs] ... folders.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// If container IDs can't be found, try fallback recovery method
if (err instanceof ContainerNotFoundError) {
this.logSvc.logWarning('Container IDs not found, attempting fallback recovery to clear bookmarks');
return this.clearNativeBookmarksFallback();
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When getNativeContainerIds() rejects with ContainerNotFoundError, this branch returns clearNativeBookmarksFallback() directly. If the fallback itself fails (e.g., browser.bookmarks.getTree() rejects), the caller will now receive a raw error instead of the existing FailedRemoveNativeBookmarksError wrapper used by the non-fallback path. Consider wrapping any fallback failure in FailedRemoveNativeBookmarksError as well to keep clearNativeBookmarks() error semantics consistent.

Suggested change
return this.clearNativeBookmarksFallback();
return this.clearNativeBookmarksFallback().catch((fallbackErr) => {
throw new FailedRemoveNativeBookmarksError(undefined, fallbackErr);
});

Copilot uses AI. Check for mistakes.
Comment on lines +519 to +531
// Fallback: try to find containers by position if hardcoded IDs don't match
// In Chromium browsers, root typically has exactly 2 children: toolbar (index 0) and other (index 1)
if ((!otherBookmarksNode || !toolbarBookmarksNode) && root.children && root.children.length === 2) {
// Try to identify by position - typically toolbar is first, other is second
if (!toolbarBookmarksNode && root.children[0]) {
toolbarBookmarksNode = root.children[0];
this.logSvc.logInfo(`Found toolbar bookmarks by position: ${toolbarBookmarksNode.id}`);
}
if (!otherBookmarksNode && root.children[1]) {
otherBookmarksNode = root.children[1];
this.logSvc.logInfo(`Found other bookmarks by position: ${otherBookmarksNode.id}`);
}
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The position-based fallback only runs when root.children.length === 2, but many Chromium bookmark trees have 3+ root children (e.g., including “Mobile bookmarks”). If IDs differ from the hardcoded values in those cases, this fallback will never trigger and ContainerNotFoundError will still be thrown. Consider loosening this condition (e.g., require >= 2 and pick indices 0/1, or add additional heuristics) so the fallback can help on more Chromium variants.

Copilot uses AI. Check for mistakes.
Comment on lines +132 to +136
root.children.forEach((child) => {
if (child.children && child.children.length > 0) {
findAndClearXbsContainers(child.children);
}
});
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clearNativeBookmarksFallback() only calls findAndClearXbsContainers(child.children) for each root.children entry, so it never checks the root.children nodes themselves for [xbs] ... titles (despite the comment saying it searches “root children and their descendants”). Consider running findAndClearXbsContainers(root.children) (or explicitly checking each root child) so the fallback also works if an xBrowserSync container ever exists directly under the root.

Suggested change
root.children.forEach((child) => {
if (child.children && child.children.length > 0) {
findAndClearXbsContainers(child.children);
}
});
findAndClearXbsContainers(root.children);

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants