Protocol error (Page.navigate): Target closed
Learn how to fix the 'Target closed' error when trying to navigate to a page that has been closed
Ivan Muñoz
Apr 30, 2025
Crash

This error occurs when you try to perform an action on a page or browser that has already been closed. This typically happens due to premature closure or race conditions in your automation code.
Common Causes
- Premature browser closure: Browser is closed before navigation completes
- Multiple page closures: Trying to use a page after it’s been closed
- Race conditions: Operations running after page/browser closure
- Error handling issues: Browser closes during error recovery
- Resource cleanup: Automatic cleanup closing resources too early
Solutions
1. Proper browser and page lifecycle management
let browser;
let page;
try {
browser = await puppeteer.launch();
page = await browser.newPage();
await page.goto('https://example.com');
// ... your automation code ...
} catch (error) {
console.error('Error:', error);
} finally {
if (page) await page.close();
if (browser) await browser.close();
}
2. Check page state before operations
async function safeNavigate(page, url) {
if (!page || page.isClosed()) {
throw new Error('Page is closed or invalid');
}
try {
await page.goto(url);
} catch (error) {
if (error.message.includes('Target closed')) {
console.log('Page was closed during navigation');
// Handle the error appropriately
}
throw error;
}
}
3. Implement proper error handling
async function runAutomation() {
const browser = await puppeteer.launch();
const page = await browser.newPage();
try {
await page.goto('https://example.com');
// ... your automation code ...
} catch (error) {
if (error.message.includes('Target closed')) {
console.log('Target was closed, attempting recovery...');
// Implement recovery logic
const newPage = await browser.newPage();
await newPage.goto('https://example.com');
return newPage;
}
throw error;
}
}
4. Use page event listeners
const page = await browser.newPage();
// Listen for page close events
page.on('close', () => {
console.log('Page was closed');
});
// Listen for browser disconnect
browser.on('disconnected', () => {
console.log('Browser was disconnected');
});
5. Implement retry logic with proper checks
async function navigateWithRetry(page, url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
if (page.isClosed()) {
throw new Error('Page is closed');
}
await page.goto(url);
return;
} catch (error) {
if (i === maxRetries - 1) throw error;
console.log(`Retry ${i + 1} of ${maxRetries}`);
// Wait before retrying
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
}
Still Encountering Issues?
If you’re still having trouble with target closure errors, you can use a visual testing tool like Buglesstack to debug your automation and track page lifecycle events.
try {
await page.goto('https://www.google.com/search?q=puppeteer');
await page.waitForSelector('[name="q"]');
}
catch (error) {
// Prepare buglesstack data
const buglesstackData = {
url: page.url(),
screenshot: await page.screenshot({ encoding: 'base64' }),
html: await page.content(),
metadata: {},
message: error.message,
stack: error.stack
};
// Get your access token from https://app.buglesstack.com
const ACCESS_TOKEN = 'HERE_YOUR_ACCESS_TOKEN';
// Send error to buglesstack
await axios.post('https://app.buglesstack.com/api/v1/crashes', buglesstackData, {
headers: {
Authorization: `Bearer ${ACCESS_TOKEN}`,
'Content-Type': 'application/json'
}
});
// Re-throw the error to propagate it
throw error;
}
By implementing proper lifecycle management and error handling, you can resolve the “Target closed” error and make your automation more robust.