{"record":{"id":"f029a676319f47ea","repo":"GopeedLab/gopeed","slug":"network-request-timed-out","errorCode":null,"errorMessage":"Network request timed out","messagePattern":"Network request timed out","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/download/engine/inject/stream/module.go","lineNumber":760,"sourceCode":"\t}\n\tclient.SetRedirectPolicy(func(req *http.Request, via []*http.Request) error {\n\t\tswitch reqMeta.Redirect {\n\t\tcase \"manual\":\n\t\t\treturn http.ErrUseLastResponse\n\t\tcase \"error\":\n\t\t\treturn fmt.Errorf(\"redirect failed\")\n\t\tdefault:\n\t\t\tif len(via) > 20 {\n\t\t\t\treturn fmt.Errorf(\"too many redirects\")\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t})\n\tresp, err := reqBuilder.Send(reqMeta.Method, reqMeta.URL)\n\tif err != nil {\n\t\tvar ne net.Error\n\t\tif errorsAsTimeout(err, &ne) {\n\t\t\treturn nil, fmt.Errorf(\"Network request timed out\")\n\t\t}\n\t\treturn nil, fmt.Errorf(\"Network request failed: %w\", err)\n\t}\n\tid := fmt.Sprintf(\"%d\", time.Now().UnixNano())\n\tmeta := &fetchOpenMeta{\n\t\tID:         id,\n\t\tStatus:     resp.StatusCode,\n\t\tStatusText: resp.Status,\n\t\tURL:        reqMeta.URL,\n\t}\n\tif resp.Response != nil && resp.Response.Request != nil && resp.Response.Request.URL != nil {\n\t\tresponseURL := *resp.Response.Request.URL\n\t\tresponseURL.Fragment = \"\"\n\t\tmeta.URL = responseURL.String()\n\t}\n\tfor key, values := range resp.Header {\n\t\tmeta.Headers = append(meta.Headers, [2]string{key, strings.Join(values, \", \")})\n\t}","sourceCodeStart":742,"sourceCodeEnd":778,"githubUrl":"https://github.com/GopeedLab/gopeed/blob/7b7327ffb30816273a74b142cccc0bc10c5a4c67/pkg/download/engine/inject/stream/module.go#L742-L778","documentation":"After reqBuilder.Send() fails, the injected fetch implementation checks errorsAsTimeout: if the error implements net.Error with Timeout() true (or unwraps to one), it reports 'Network request timed out' without the underlying detail. It means the HTTP request was aborted by a deadline, not refused or reset.","triggerScenarios":"Server accepting the connection but responding slower than the request timeout; a stalled proxy or VPN that stops forwarding bytes; DNS/CONNECT phases exceeding the client timeout during gopeed.fetch().","commonSituations":"Slow CDNs or rate-limited hosts during resolve; mobile/edge networks with high latency; a proxy configured in downloader settings that hangs; large HEAD requests to servers that compute metadata on demand.","solutions":["Retry the request — timeouts are frequently transient","Check/disable the configured proxy to rule out a stalling middlebox","Test the same URL with curl to confirm the server is genuinely slow, and prefer a faster mirror if so"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function fetchWithRetry(url, attempts = 3) {\n  for (let i = 0; i < attempts; i++) {\n    try {\n      return await fetch(url);\n    } catch (e) {\n      if (String(e).includes('Network request timed out') && i < attempts - 1) {\n        await new Promise(r => setTimeout(r, 500 * (i + 1)));\n        continue;\n      }\n      throw e;\n    }\n  }\n}","preventionTips":["Retry timeouts with linear/exponential backoff before surfacing them to the user","Verify proxy health when timeouts cluster across many hosts","Prefer HEAD probes for resolve logic to cut time-to-timeout on slow servers"],"tags":["network","fetch","timeout","http","extension"],"backgroundTag":null,"analyzedSha":"7b7327ffb30816273a74b142cccc0bc10c5a4c67","analyzedAt":"2026-08-16T02:51:03.250Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}