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


Protocol error (Page.navigate): Target closed

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.

Save days debugging
pptr crashes

Speed up production debugging with instant visualisations of your puppeteer crashes.