Debugging and Troubleshooting dApp Connection Issues with Nautilus Wallet: A Complete Developer Guide

The most common fixes for Nautilus Wallet connection failures involve verifying the content script injection in injected.ts, checking the IndexedDB connectedDApps store for the origin entry, and ensuring the background service worker successfully opens the approval popup via createWindow in src/common/uiHelpers.ts.

Nautilus Wallet is a popular browser extension for interacting with the Ergo blockchain, but developers often encounter friction when establishing connections between decentralized applications (dApps) and the wallet. Understanding the internal message flow and state management within the nautls/nautilus-wallet repository is essential for effectively debugging and troubleshooting dApp connection issues with Nautilus Wallet. This guide walks through the connection architecture, identifies common failure points, and provides concrete diagnostic snippets.

Understanding the Nautilus Connection Architecture

The connection flow relies on a multi-layer message passing system between the dApp, content script, background service worker, and popup UI. According to the source code in src/extension/content-scripts/injected.ts and src/extension/background/background.ts, the process follows five distinct steps:

  1. dApp Initiates Request: The dApp calls window.ergoConnector.nautilus.connect() (or the legacy window.ergo_request_read_access). The injected content script sends an ExternalRequest.Connect message to the background via webext-bridge using sendMessage.

  2. Background Validates Origin: The background script receives the request as InternalRequest.Connect and verifies the request originates from an internal endpoint. It checks connectedDAppsDbService.getByOrigin to see if the dApp is already authorized.

  3. User Approval Flow: If unauthorized, the background opens a popup window. The connector router (src/extension/connector/router.ts) handles the /connect route, and the popup UI writes the approval to the database via connectedDAppsDbService.put.

  4. Connection Established: The background stores the approval and replies true to the content script. The content script stores the API object in window.ergo if createErgoObject was requested.

  5. Subsequent API Calls: Methods like get_utxos or sign_tx route through the same message channel, with the background checking connectedDAppsDbService via the onMessageAuth guard before fulfilling requests.

The connection state persists in the connectedDAppsDbService IndexedDB table and is validated on every internal request. Any break in this chain results in "Not connected" or "Refused" errors.

Common Failure Points and Diagnostic Strategies

When debugging and troubleshooting dApp connection issues with Nautilus Wallet, symptoms typically cluster around specific architectural failure points. Use the following diagnostic approach based on the source code in src/extension/background/background.ts and related files.

Connection Resolves to False or Popup Never Opens

If window.ergoConnector.nautilus.connect() resolves to false, the popup window likely failed to open or was blocked by the browser.

Open Extension → Service Workers in Chrome DevTools and check the console for openWindow errors. Verify that createWindow in src/common/uiHelpers.ts succeeded and that the extension manifest includes the activeTab permission required for window creation.

window.ergo Remains Undefined After Connection

When window.ergo is undefined despite a successful connection, the createErgoObject flag was likely set to false or the connection was implicitly denied.

Inspect the content script console for the resolution log in connect() (line 33 of injected.ts). Check the boolean return value to confirm whether the API object should have been injected.

"Not Connected" Errors on API Calls

If the dApp receives { code: 400, info: "Not connected." } when calling get_utxos or similar methods, the background cannot find a matching entry in the connection database.

Open the IndexedDB panel in DevTools and inspect the connectedDApps store managed by connectedDAppsDbService. Verify the record contains the correct origin and walletId matching the current dApp domain.

Signing Requests Hang or Return Invalid Params

When sign_tx or data signing requests hang or return validation errors, the payload may be malformed or the address might not belong to the connected wallet.

Check the background logs for handleDataSigningRequest validation (lines 19-24 in the relevant handler). Confirm the requested address exists in addressesDbService and is associated with the currently connected wallet ID.

Permission Denied in UI Despite User Approval

If the popup shows "Permission denied" even after the user clicks Allow, the graphQLService URL may be mismatched or the backend connection failed.

Check the InternalEvent.UpdatedBackendUrl listener (lines 51-54 in background handlers) and confirm the URL stored in browser.storage matches the active backend endpoint.

No Background Console Messages Appear

When no messages appear in the background console, the content script likely failed to inject, often due to Content Security Policy (CSP) restrictions.

Open the page’s Sources tab and verify injected.js is loaded. If blocked by CSP, test on a non-CSP page or adjust the server headers to allow the extension script.

Practical Debugging Snippets

Use these console commands and code blocks to inspect the connection state directly in the browser environment.

Testing the Connection Flow

Run this in your dApp console to verify the basic connection handshake:

window.ergoConnector.nautilus
  .connect()
  .then(granted => console.log('Connect granted?', granted))
  .catch(err => console.error('Connect error', err));

If the promise rejects, the error object contains the APIErrorCode defined in src/types/connector.ts.

Logging Bridge Messages in the Background

Add this temporary listener to the background service worker console to trace all message traffic:

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  console.log('Bridge message →', msg.type, msg);
  return true; // keep the channel open
});

Verifying the Database Entry

Check if the connection persisted correctly by querying the IndexedDB service directly:

connectedDAppsDbService.getByOrigin(window.location.origin)
  .then(conn => console.log('DB entry →', conn))
  .catch(e => console.error('DB error', e));

Resetting the Connection State

Force a clean reconnection when the state becomes stale:

await window.ergoConnector.nautilus.disconnect();
await window.ergoConnector.nautilus.connect();

Key Source Files for Reference

Keep these files open when debugging to trace the execution flow:

Summary

Effective debugging and troubleshooting of dApp connection issues with Nautilus Wallet requires tracing the message flow from the injected content script through the background service worker to the popup UI. Key takeaways include:

  • Verify injected.js loads correctly to ensure window.ergoConnector is available.
  • Check the IndexedDB connectedDApps store to confirm the origin is authorized.
  • Monitor the background console for createWindow errors if the approval popup fails to appear.
  • Ensure the activeTab permission is present in the extension manifest.
  • Use disconnect() followed by connect() to reset stale connection states.

Frequently Asked Questions

Why does my dApp connection resolve to false even after the user clicks Allow?

This occurs when the background service worker fails to open the approval popup or the user denies the permission. Check the background console for errors in createWindow from src/common/uiHelpers.ts and verify the extension has the activeTab permission. Additionally, ensure the connectedDAppsDbService.put call in src/extension/popup/* successfully writes the origin to IndexedDB.

How can I verify that Nautilus has stored my dApp's connection persistently?

Open the browser's DevTools, navigate to the Application (or Storage) tab, and inspect the IndexedDB connectedDApps store managed by connectedDAppsDbService.ts. Run the following in the background console to verify programmatically:

connectedDAppsDbService.getByOrigin(window.location.origin)
  .then(conn => console.log('Stored connection:', conn));

A valid entry must contain the correct origin and walletId.

What causes "Not connected" errors when calling sign_tx or get_utxos?

The background script's onMessageAuth guard (lines 40-50 in src/extension/background/background.ts) validates every API call against the connectedDAppsDbService. If the dApp's origin is missing from the database, or if the requested address does not exist in addressesDbService for the connected wallet, the request returns { code: 400, info: "Not connected." }. Verify the connection flow completed successfully and the address belongs to the user's wallet.

Where can I find background service worker logs to debug message routing?

In Chrome or Edge, open the extensions management page (chrome://extensions), enable Developer mode, and click the service worker link under the Nautilus extension. This opens a dedicated DevTools window for the background script. Look for logs related to InternalRequest.Connect, ExternalRequest.Connect, and createWindow calls. If no messages appear, the content script (injected.ts) may be blocked by a Content Security Policy and failed to inject into the page.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →