Chrome Extension Debugging Checklist — Developer Guide
5 min readExtension Debugging Checklist
This checklist provides a systematic approach to diagnosing and fixing common Chrome extension issues. Each section covers a specific problem area with symptoms, likely causes, diagnostic steps, and fixes.
Table of Contents
- Manifest Issues
- Service Worker Issues
- Content Script Issues
- Messaging Issues
- Storage Issues
- UI Issues
Manifest Issues
Symptom: Extension fails to load or shows errors in chrome://extensions
Likely Causes:
- Syntax errors in manifest.json
- Missing required fields
- Invalid permission names or host permissions
- Incorrect manifest version
How to Diagnose:
- Open
chrome://extensionsand look for error messages under your extension - Validate manifest.json using Chrome Extension Manifest Validator
- Check for trailing commas or malformed JSON
How to Fix:
{
"manifest_version": 3,
"name": "My Extension",
"version": "1.0",
"permissions": ["storage", "tabs"],
"host_permissions": ["<all_urls>"]
}
- Ensure all required fields are present: name, version, manifest_version
- Use correct permission names from Chrome’s API documentation
- Remove unused permissions to avoid unnecessary warnings
Service Worker Issues
Symptom: Service worker not registering or not responding to events
Likely Causes:
- Service worker file missing or path incorrect
- Event listeners registered inside async functions
- Service worker terminated due to inactivity (30-second timeout)
How to Diagnose:
- Open
chrome://extensions, click “Inspect views: service worker” - Check
chrome://serviceworker-internalsfor registration status - Look for console errors on SW startup
How to Fix:
- Register listeners at top level, not inside async functions: ```javascript // Correct: synchronous top-level registration chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { // handler });
// Persist state to survive restarts chrome.storage.local.set({ key: value });
### Symptom: Lost state after service worker restarts {#symptom-lost-state-after-service-worker-restarts}
**Likely Causes:**
- Storing state in global variables
- Service worker lifecycle terminates and resets memory
**How to Diagnose:**
1. Add console.log at SW startup to detect restarts
2. Check chrome.storage for persisted state
**How to Fix:**
- Use `chrome.storage.session` for temporary state
- Use `chrome.storage.local` for persistent state
- Re-initialize state on each SW startup
---
## Content Script Issues {#content-script-issues}
### Symptom: Content script not injecting or not running {#symptom-content-script-not-injecting-or-not-running}
**Likely Causes:**
- Incorrect match patterns in manifest
- Wrong `run_at` timing
- Page conditions not met (SPA navigation, dynamic content)
**How to Diagnose:**
1. Open DevTools on the target page, check "Content scripts" in Sources panel
2. Verify match patterns match the current URL
3. Check if script is declared under `content_scripts` in manifest
**How to Fix:**
```json
{
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_idle"
}]
}
- Use
document_idleinstead ofdocument_endfor SPAs - Use
chrome.scripting.executeScriptfor dynamic injection
Symptom: CSS conflicts with page styles
Likely Causes:
- Global CSS selectors affecting page elements
- Specificity issues with existing page styles
How to Diagnose:
- Inspect elements in DevTools to see applied styles
- Check for extension styles bleeding into page
How to Fix:
- Use unique class prefixes for extension styles
- Use Shadow DOM for complete isolation
- Scope styles to specific container elements
Messaging Issues
Symptom: Messages not delivered or no response
Likely Causes:
- No listener registered in destination context
- Missing
return truefor async responses - Wrong tabId or extension context
How to Diagnose:
- Add console.log in both sender and receiver
- Check “Could not establish connection” errors in console
- Verify sender and receiver contexts are active
How to Fix:
// Content script - sender
chrome.runtime.sendMessage({ type: 'GET_DATA' });
// Service worker - receiver with async response
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'GET_DATA') {
asyncOperation().then(result => sendResponse(result));
return true; // Keep channel open for async response
}
});
Symptom: “The message port closed before a response was received”
Likely Causes:
- Async handler didn’t return
trueto keep channel open - Response sent after the port closed
How to Fix:
- Always return
truefrom onMessage listener when using async sendResponse - Use Promise-based messaging libraries for reliability
- Implement retry logic for message delivery
Storage Issues
Symptom: Storage quota exceeded errors
Likely Causes:
- Storage quota exceeded (typically 10MB for local, 100KB for sync)
- Storing large objects or media files
How to Diagnose:
- Check chrome.storage.local.getBytesInUse()
- Compare against quota constants like
chrome.storage.local.QUOTA_BYTES
How to Fix:
- Implement storage cleanup and rotation policies
- Store only essential data; offload large data to IndexedDB
- Use compression for stored strings
Symptom: sync vs local confusion
Likely Causes:
- Using chrome.storage.sync when data doesn’t need to sync
- Data not persisting across installs when using sync
How to Diagnose:
- Check if data appears in chrome://settings
- Verify storage type matches use case
How to Fix:
- Use
chrome.storage.localfor device-specific data - Use
chrome.storage.syncfor user preferences that should follow their account - Use
chrome.storage.sessionfor temporary in-memory data
UI Issues
Symptom: Popup not showing or showing blank
Likely Causes:
- Popup HTML missing or path incorrect
- JavaScript errors in popup
- CSP (Content Security Policy) blocking scripts
How to Diagnose:
- Right-click extension icon -> “Inspect popup”
- Check Console for errors
- Verify popup path in manifest
How to Fix:
{
"action": {
"default_popup": "popup.html",
"default_icon": "icon.png"
}
}
- Ensure popup.html exists and loads without errors
- Avoid inline scripts; use external JS files
- Check CSP headers on chrome-extension:// URLs
Symptom: CSP blocking extension functionality
Likely Causes:
- Inline scripts or styles blocked by CSP
- External requests not allowed
How to Fix:
- Move inline scripts to external files
- Use chrome.runtime.getURL() for extension resources
- Declare content_security_policy in manifest if needed (Manifest V3 restricts this)
Cross-references
- Debugging Extensions Guide - General debugging fundamentals
- Advanced Debugging - Deep-dive debugging techniques
- Service Worker Debugging - Detailed SW lifecycle debugging
Related Articles
Related Articles
Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.