Short answer first
The premise needs correcting before the questions can be answered: as of current Hugo releases, resources.GetRemote has no Force option and no documented built-in retry loop. It either returns the remote resource, serves it from the on-disk cache, or returns an error. Because of that, the "retry overwrites the cached file" scenario described in the question does not match how the function actually behaves, and duplicate files in public/ are not a normal outcome of any of these paths.
What is confirmed versus assumed
Well-established behavior:
- Successful responses are cached on disk (by default under the Hugo cache dir, e.g.
resources/_gen or the configured caches.getremote.dir), keyed by a hash of the URL plus the options map. - Cache retention is controlled by
caches.getremote.maxAge. A value of -1 keeps entries indefinitely; 0 effectively disables reuse, which is the closest thing to a "force" flag. - Changing any option (headers, method, body) changes the cache key and forces a fresh fetch — a deliberate cache-busting technique.
- On failure, Hugo returns an error (or nil resource depending on error handling); it does not silently serve stale content, and there is no documented automatic retry-with-backoff inside the function.
Uncertain / version-dependent: exact defaults, config key names, and error-vs-non-2xx handling vary across Hugo versions. Verify against your installed version (hugo version) before relying on specifics.
Answers to the three questions
- Retry with "Force = false" producing a second copy: There is no retry mechanism or Force flag, so this condition cannot arise from GetRemote itself. If you see two copies of a resource in
public/, the more likely causes are calling GetRemote with different option maps (different cache keys, published under different hashed filenames) or publishing the resource under two different paths in templates. - Force overwriting the cache: Since no such flag exists, the equivalent operations are clearing the cache (
hugo --gc, or deleting the getremote cache directory) or setting maxAge: 0. These affect fetching, not output naming — the published filename derives from the resource path, so a re-fetch replaces the same output file rather than duplicating it. For concurrent builds, the real risk is two processes sharing one cache directory; give each build its own cache dir (via caches.getremote.dir or --cacheDir) to avoid contention. Even then, cache races affect fetch integrity, not the count of files in public/. - File count after a failed first attempt and later success: One. A failed fetch publishes nothing; a later successful fetch publishes exactly one file. There is no partial or orphaned output from the failed attempt under normal behavior.
How to verify on your setup
hugo version
hugo --logLevel info # watch whether GetRemote hits the network or cache
hugo --gc # clear caches, then rebuild and compare output
If you are genuinely observing duplicate files, the one missing diagnostic that would change this answer is the actual template call: share the resources.GetRemote invocation (URL and options map) and the two differing output paths, since distinct option maps are the most plausible duplicate source.