{"record":{"id":"e59d45052a3634d0","repo":"go-task/task","slug":"checking-remote-file-w","errorCode":null,"errorMessage":"checking remote file: %w","messagePattern":"checking remote file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"taskfile/taskfile.go","lineNumber":52,"sourceCode":")\n\n// RemoteExists will check if a file at the given URL Exists. If it does, it\n// will return its URL. If it does not, it will search the search for any files\n// at the given URL with any of the default Taskfile files names. If any of\n// these match a file, the first matching path will be returned. If no files are\n// found, an error will be returned.\nfunc RemoteExists(ctx context.Context, u url.URL, client *http.Client) (*url.URL, error) {\n\t// Create a new HEAD request for the given URL to check if the resource exists\n\treq, err := http.NewRequestWithContext(ctx, \"HEAD\", u.String(), nil)\n\tif err != nil {\n\t\treturn nil, errors.TaskfileFetchFailedError{URI: u.Redacted()}\n\t}\n\n\t// Request the given URL\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\tif ctx.Err() != nil {\n\t\t\treturn nil, fmt.Errorf(\"checking remote file: %w\", ctx.Err())\n\t\t}\n\t\treturn nil, errors.TaskfileFetchFailedError{URI: u.Redacted()}\n\t}\n\tdefer resp.Body.Close()\n\n\t// If the request was successful and the content type is allowed, return the\n\t// URL The content type check is to avoid downloading files that are not\n\t// Taskfiles It means we can try other files instead of downloading\n\t// something that is definitely not a Taskfile\n\tcontentType := resp.Header.Get(\"Content-Type\")\n\tif resp.StatusCode == http.StatusOK && slices.ContainsFunc(allowedContentTypes, func(s string) bool {\n\t\treturn strings.Contains(contentType, s)\n\t}) {\n\t\treturn &u, nil\n\t}\n\n\t// If the request was not successful, append the default Taskfile names to\n\t// the URL and return the URL of the first successful request","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/go-task/task/blob/385e5ad92af02877b6d7cf9dcc963b5ed916e70a/taskfile/taskfile.go#L34-L70","documentation":"RemoteExists in taskfile/taskfile.go wraps context errors when performing the HTTP HEAD/GET used to check whether a remote taskfile exists. It is thrown when the request fails specifically because the caller-supplied context was cancelled or its deadline expired while the HTTP client was executing. Any other request failure becomes a TaskfileFetchFailedError instead.","triggerScenarios":"Reading a remote taskfile (ReadContext -> RemoteExists) with a context that is cancelled by the caller, or whose deadline/timeout elapses before the server responds, so client.Do returns an error while ctx.Err() != nil.","commonSituations":"Slow or unreachable remote host combined with a short context deadline (e.g. context.WithTimeout of a few seconds), user Ctrl-C aborting a long-running task that fetches remote taskfiles, or CI jobs with tight per-step timeouts.","solutions":["Increase the context deadline passed to ReadContext (e.g. context.WithTimeout(ctx, 30*time.Second)) or remove the deadline if latency is expected.","Check network connectivity / DNS / proxy settings for the remote host, since a hanging connection often is what exhausts the deadline.","Retry the fetch with a fresh non-cancelled context once the cancellation cause (signal, parent timeout) is resolved.","If your code cancels intentionally, stop propagating the error and treat it as an intentional abort."],"exampleFix":"// before\nctx, cancel := context.WithTimeout(ctx, 2*time.Second)\nnode.ReadContext(ctx)\n// after\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()\nnode.ReadContext(ctx)","handlingStrategy":"retry","validationCode":"// before fetching, ensure the context has sane headroom\nif deadline, ok := ctx.Deadline(); ok && time.Until(deadline) < 5*time.Second {\n    return errors.New(\"context deadline too short for remote taskfile fetch\")\n}","typeGuard":null,"tryCatchPattern":"tf, err := node.ReadContext(ctx)\nvar ce error\nif err != nil && errors.As(err, &ce) && ctx.Err() != nil {\n    if errors.Is(ctx.Err(), context.DeadlineExceeded) {\n        ctx = extendDeadline(ctx)\n        tf, err = node.ReadContext(ctx) // retry once\n    } else {\n        return err // caller cancelled intentionally\n    }\n}","preventionTips":["Set generous timeouts (>=10s) for remote taskfile fetches.","Keep network/proxy config healthy; test the URL with curl first.","Distinguish intentional cancellation from timeouts in your code.","Retry once with a fresh context on DeadlineExceeded."],"tags":["network","context-cancelled","timeout","http"],"backgroundTag":"context-canceled","analyzedSha":"385e5ad92af02877b6d7cf9dcc963b5ed916e70a","analyzedAt":"2026-09-05T09:01:05.226Z","contentChangedAt":"2026-09-05T09:01:05.226Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}