Skip to content

Commit 40156b6

Browse files
committed
fix: resolve URL loading timeout issues in @ mentions
## Problem URLs provided through @ mentions were failing to load with "Navigation timeout of 10000 ms exceeded" errors, preventing users from fetching web content for AI assistance. ## Solution - **Increased timeout limits**: Extended UrlContentFetcher timeout from 10s to 30s and BrowserSession timeout from 7s to 15s for better reliability with slow-loading websites - **Added fallback retry logic**: If networkidle2 fails, automatically retry with domcontentloaded only (20s timeout) to handle JavaScript-heavy sites - **Improved error handling**: Enhanced error messages with specific guidance for timeout, DNS, network, and HTTP status errors - **Enhanced browser compatibility**: Added Chrome launch arguments (--no-sandbox, --disable-web-security, etc.) and set proper viewport/headers to reduce blocking by websites ## Files Changed - `src/services/browser/UrlContentFetcher.ts`: Increased timeout, added retry logic, enhanced browser setup - `src/services/browser/BrowserSession.ts`: Increased navigation timeouts for consistency - `src/core/mentions/index.ts`: Improved error handling with user-friendly messages ## Impact Users can now successfully fetch content from slower websites and receive clearer error messages when issues occur, significantly improving the @ mention URL feature reliability. Fixes #1430
1 parent 992997c commit 40156b6

File tree

3 files changed

+54
-6
lines changed

3 files changed

+54
-6
lines changed

src/core/mentions/index.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,24 @@ export async function parseMentions(
9898
const markdown = await urlContentFetcher.urlToMarkdown(mention)
9999
result = markdown
100100
} catch (error) {
101-
vscode.window.showErrorMessage(`Error fetching content for ${mention}: ${error.message}`)
102-
result = `Error fetching content: ${error.message}`
101+
console.error(`Error fetching URL ${mention}:`, error)
102+
103+
// Provide more helpful error messages based on error type
104+
let errorMessage = error.message
105+
if (error.message.includes("timeout")) {
106+
errorMessage = `The website took too long to load (timeout). This could be due to a slow connection, heavy website, or the site being temporarily unavailable. You can try again later or check if the URL is correct.`
107+
} else if (error.message.includes("net::ERR_NAME_NOT_RESOLVED")) {
108+
errorMessage = `The website address could not be found. Please check if the URL is correct and try again.`
109+
} else if (error.message.includes("net::ERR_INTERNET_DISCONNECTED")) {
110+
errorMessage = `No internet connection. Please check your network connection and try again.`
111+
} else if (error.message.includes("403") || error.message.includes("Forbidden")) {
112+
errorMessage = `Access to this website is forbidden. The site may block automated access or require authentication.`
113+
} else if (error.message.includes("404") || error.message.includes("Not Found")) {
114+
errorMessage = `The page was not found. Please check if the URL is correct.`
115+
}
116+
117+
vscode.window.showErrorMessage(`Error fetching content for ${mention}: ${errorMessage}`)
118+
result = `Error fetching content: ${errorMessage}`
103119
}
104120
}
105121
parsedText += `\n\n<url_content url="${mention}">\n${result}\n</url_content>`

src/services/browser/BrowserSession.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ export class BrowserSession {
320320
* Navigate to a URL with standard loading options
321321
*/
322322
private async navigatePageToUrl(page: Page, url: string): Promise<void> {
323-
await page.goto(url, { timeout: 7_000, waitUntil: ["domcontentloaded", "networkidle2"] })
323+
await page.goto(url, { timeout: 15_000, waitUntil: ["domcontentloaded", "networkidle2"] })
324324
await this.waitTillHTMLStable(page)
325325
}
326326

@@ -403,7 +403,7 @@ export class BrowserSession {
403403
console.log(`Root domain: ${this.getRootDomain(currentUrl)}`)
404404
console.log(`New URL: ${normalizedNewUrl}`)
405405
return this.doAction(async (page) => {
406-
await page.reload({ timeout: 7_000, waitUntil: ["domcontentloaded", "networkidle2"] })
406+
await page.reload({ timeout: 15_000, waitUntil: ["domcontentloaded", "networkidle2"] })
407407
await this.waitTillHTMLStable(page)
408408
})
409409
}
@@ -476,7 +476,7 @@ export class BrowserSession {
476476
await page
477477
.waitForNavigation({
478478
waitUntil: ["domcontentloaded", "networkidle2"],
479-
timeout: 7000,
479+
timeout: 15000,
480480
})
481481
.catch(() => {})
482482
await this.waitTillHTMLStable(page)

src/services/browser/UrlContentFetcher.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,28 @@ export class UrlContentFetcher {
4848
this.browser = await stats.puppeteer.launch({
4949
args: [
5050
"--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
51+
"--no-sandbox",
52+
"--disable-setuid-sandbox",
53+
"--disable-dev-shm-usage",
54+
"--disable-accelerated-2d-canvas",
55+
"--no-first-run",
56+
"--no-zygote",
57+
"--disable-gpu",
58+
"--disable-web-security",
59+
"--disable-features=VizDisplayCompositor",
5160
],
5261
executablePath: stats.executablePath,
5362
})
5463
// (latest version of puppeteer does not add headless to user agent)
5564
this.page = await this.browser?.newPage()
65+
66+
// Set additional page configurations to improve loading success
67+
if (this.page) {
68+
await this.page.setViewport({ width: 1280, height: 720 })
69+
await this.page.setExtraHTTPHeaders({
70+
"Accept-Language": "en-US,en;q=0.9",
71+
})
72+
}
5673
}
5774

5875
async closeBrowser(): Promise<void> {
@@ -71,7 +88,22 @@ export class UrlContentFetcher {
7188
- domcontentloaded is when the basic DOM is loaded
7289
this should be sufficient for most doc sites
7390
*/
74-
await this.page.goto(url, { timeout: 10_000, waitUntil: ["domcontentloaded", "networkidle2"] })
91+
try {
92+
await this.page.goto(url, {
93+
timeout: 30_000, // Increased from 10_000 to 30_000 (30 seconds)
94+
waitUntil: ["domcontentloaded", "networkidle2"],
95+
})
96+
} catch (error) {
97+
// If networkidle2 fails, try with just domcontentloaded as fallback
98+
console.warn(
99+
`Failed to load ${url} with networkidle2, retrying with domcontentloaded only: ${error.message}`,
100+
)
101+
await this.page.goto(url, {
102+
timeout: 20_000, // 20 seconds for fallback
103+
waitUntil: ["domcontentloaded"],
104+
})
105+
}
106+
75107
const content = await this.page.content()
76108

77109
// use cheerio to parse and clean up the HTML

0 commit comments

Comments
 (0)