Skip to content

Make fetched-content filenames collision-proof - #2018

Merged
Aaronontheweb merged 2 commits into
devfrom
fix/webfetch-filename-collision
Aug 19, 2026
Merged

Make fetched-content filenames collision-proof#2018
Aaronontheweb merged 2 commits into
devfrom
fix/webfetch-filename-collision

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Collaborator

Bug

WebFetchTool built the saved-content filename from a second-precision
timestamp only (WebFetchTool.cs:269). Two fetches of the same URL
inside one second built the same filename.

File.WriteAllBytes and File.WriteAllText both truncate an existing
file. The second fetch overwrote the first one, silently, with no
error or warning. The first fetch's content was gone, and the tool
result for the first fetch still pointed to a path that now held the
second fetch's content.

This is a sibling of the reminder execution child-name collision fixed
in 30ff5d2 ("Name reminder execution children by sequence, not by
millisecond"): a timestamp collided when two events landed inside one
tick, only there the actor name collision threw, so the bug surfaced
as a crash. Here it fails silently as data loss, which is worse.

Fix

Add a short random suffix (first 8 hex characters of a guid) to the
saved-content filename. Keep the second-precision timestamp for a
human reading the filename. This matches the established pattern in
WebhookExecutionService.cs:42, which appends a full guid segment to
the actor name for the same reason.

Test

Added ExecuteAsync_same_url_same_frozen_second_saves_two_distinct_files
to WebFetchToolTests. It freezes the clock at one second with
FakeTimeProvider and fetches the same URL twice. Before the fix this
produces one file on disk with only the second fetch's content; after
the fix it produces two distinct files, each holding its own fetch's
content. No sleeps, no bounded waits — the clock is frozen
deterministically.

Validation

  • dotnet build --nologo -v q — 0 warnings, 0 errors
  • dotnet test src/Netclaw.Actors.Tests --no-build --nologo --filter "FullyQualifiedName~WebFetchTool" — 70 passed, 0 failed
  • dotnet slopwatch analyze — 0 issues
  • pwsh -NoProfile -File ./scripts/Add-FileHeaders.ps1 -Verify — all files have headers

WebFetchTool built each saved-content filename from a second-precision
timestamp only. Two fetches of the same URL inside one second built
the same filename. File.WriteAllBytes and File.WriteAllText both
truncate an existing file, so the second fetch overwrote the first
one with no error and no warning.

Add a short random suffix to the filename. Keep the timestamp for a
human to read. The random suffix gives real uniqueness, matching the
pattern in WebhookExecutionService (a guid segment on the actor
name).

This bug is a sibling of the reminder execution child-name collision
fixed in 30ff5d2: a millisecond timestamp collided when two fires
landed inside one tick.

Add a regression test with a frozen clock. Two fetches of the same
URL at the same frozen second now produce two distinct files, and
both keep their own content on disk.
@Aaronontheweb
Aaronontheweb enabled auto-merge (squash) August 19, 2026 19:40
Comment on lines +804 to +807
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = content
};
The guid suffix owns uniqueness. The timestamp's only job is human
readability and name-sort order, and at second precision two fetches
in the same second sort by random guid instead of fetch order.
@Aaronontheweb Aaronontheweb changed the title Make fetched-content filenames collision-proof within one second Make fetched-content filenames collision-proof Aug 19, 2026
@Aaronontheweb Aaronontheweb added tools Issues related to agent tools: file_read, web_search, shell_execute, image processing, etc. search Web search backends (SearXNG, Brave, DuckDuckGo) and the web_search/web_fetch tools. bug Something isn't working labels Aug 19, 2026
@Aaronontheweb
Aaronontheweb merged commit 4be1dae into dev Aug 19, 2026
23 checks passed
@Aaronontheweb
Aaronontheweb deleted the fix/webfetch-filename-collision branch August 19, 2026 20:36
@Aaronontheweb Aaronontheweb mentioned this pull request Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working search Web search backends (SearXNG, Brave, DuckDuckGo) and the web_search/web_fetch tools. tools Issues related to agent tools: file_read, web_search, shell_execute, image processing, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant