You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Git LFS is switched on for images and other binary files in .gitattributes, but the files that were already in the repo were never converted to LFS. The two halves disagree, so 34 binary files show up as "modified" in a clean checkout even though nobody has touched them.
I hit this in a fresh workspace: git status listed 26 modified images, logos, and videos I had never opened. I checked every one of them byte by byte — all 26 are identical to what is committed. Nothing was actually changed.
What is actually going on
Two things have to agree for Git LFS to work, and here they don't:
.gitattributes says these files should be stored in LFS. It lists *.png, *.jpg, *.jpeg, *.gif, *.webp, *.ico, *.mp4, *.woff, *.woff2, *.ttf, *.otf, *.eot, and *.dill.
The files in the repo are stored the old way — as ordinary files, not as LFS.
When Git compares your working copy against what is committed, it first runs the file through LFS. LFS replaces the real image with a tiny 129-byte text stub (that stub is all LFS ever stores in Git; the real image lives on a separate server). Git then compares that 129-byte stub against the real image that is committed, sees two completely different things, and says "modified."
So the difference Git is reporting is not a change to the image. It is the gap between how the file is stored and how .gitattributessays it should be stored.
You can watch it happen:
$ git lfs clean -- ic_launcher.webp < ic_launcher.webp
version https://git-lfs.github.com/spec/v1
oid sha256:58ae87fa0c5b5d1562d27fd648d2c061553fe20e3ed570bde588162d01ea7a27
size 2884
→ 129 bytes
That 129-byte stub is exactly what git diff --stat reports as the "new" version:
.../mipmap-xxhdpi/ic_launcher.webp | Bin 2884 -> 129 bytes
Where it came from
9d72a1bb — "chore: add git lfs tracking and update ci workflows" (#1242), 2026-04-13. That commit added the LFS rules but did not convert the files that were already in the repo, and nothing has converted them since.
36 files match the LFS rules. Only 2 of them are actually stored in LFS:
The other 34 are in the mismatched state. In other words, LFS has been switched on for about four months and has been used for two files.
(Only 26 of the 34 showed up in my git status. Git skips this comparison when a file's timestamp still matches what it recorded at checkout, so the other 8 are quietly in the same state — they just haven't been looked at yet.)
Steps to Reproduce
Clone the repo fresh with git-lfs installed.
Run git status — or touch any tracked image, e.g. touch docs/logo/AG-UI\ logo_dark.png.
The file is listed as modified.
Confirm nothing really changed: git show HEAD:"docs/logo/AG-UI logo_dark.png" | shasum and shasum "docs/logo/AG-UI logo_dark.png" return the same hash.
Expected Behavior
A clean checkout should report a clean tree. Either the files are stored in LFS and match the rules, or the rules should not claim they are.
Why this is worth fixing rather than ignoring
It is not just noise — it is a footgun:
Anyone running git add -A or git commit -a silently converts images to LFS stubs, mixed into whatever they were actually working on. On a docs-heavy repo where people regularly touch images, that will land eventually. (I scoped a docs commit to two named files today specifically to avoid it — docs(tools): document ToolMessage.error in tool result examples #2311.)
Contributors without git-lfs installed get the 129-byte text stub instead of the image, so docs and example apps render broken images with no obvious explanation.
Every new workspace starts dirty, which trains people to ignore git status — the exact habit that lets a real accidental change slip through.
Two ways to fix it, and a recommendation
Option A — remove the LFS rules (my recommendation). Delete the LFS block from .gitattributes and keep binaries as ordinary Git files. Reasons:
LFS is already effectively unused: 2 files out of 36.
Converting the files properly would not actually shrink anyone's clone. Git history still contains the original copies, so the download stays the same size unless the history is rewritten — and rewriting history on a public protocol repo with many forks is not worth it for this.
Contributors would no longer need git-lfs installed to see images.
GitHub charges LFS bandwidth per organization, and this repo gets cloned a lot.
The amount of data involved is small: 20.3 MB across 36 files. That is unremarkable as ordinary Git files.
Option B — finish the migration. Run git add --renormalize . and commit, which converts all 34 files to LFS in one go. This gives a consistent state, but it means a 34-file binary commit that every open PR and fork has to rebase through, and it keeps the git-lfs-required-to-see-images downside.
Either option fixes the phantom-modified problem. The important thing is that the rules and the files agree.
Two related things found while looking
Both are independent of the LFS decision:
sdks/community/dart/test/client/config_test.dill is 10.5 MB — a Dart build artifact, and the single largest binary in the repo. It is half of the 20.3 MB total. Build artifacts probably should not be committed at all; this one looks accidental and is a good candidate for deletion plus a .gitignore entry.
docs/videos/Dojo-overview.mp4 (3.2 MB) is the one file where LFS would genuinely earn its keep. If there is an appetite to keep LFS for large media only, that is the file to keep it for — but it should then be migrated properly rather than left in today's mismatched state.
Environment
.gitattributes as of a40b5c08
git-lfs installed locally; 36 files match the LFS patterns, 2 are stored in LFS
Introduced in 9d72a1bb (#1242), 2026-04-13
Describe the Bug
Git LFS is switched on for images and other binary files in
.gitattributes, but the files that were already in the repo were never converted to LFS. The two halves disagree, so 34 binary files show up as "modified" in a clean checkout even though nobody has touched them.I hit this in a fresh workspace:
git statuslisted 26 modified images, logos, and videos I had never opened. I checked every one of them byte by byte — all 26 are identical to what is committed. Nothing was actually changed.What is actually going on
Two things have to agree for Git LFS to work, and here they don't:
.gitattributessays these files should be stored in LFS. It lists*.png,*.jpg,*.jpeg,*.gif,*.webp,*.ico,*.mp4,*.woff,*.woff2,*.ttf,*.otf,*.eot, and*.dill.When Git compares your working copy against what is committed, it first runs the file through LFS. LFS replaces the real image with a tiny 129-byte text stub (that stub is all LFS ever stores in Git; the real image lives on a separate server). Git then compares that 129-byte stub against the real image that is committed, sees two completely different things, and says "modified."
So the difference Git is reporting is not a change to the image. It is the gap between how the file is stored and how
.gitattributessays it should be stored.You can watch it happen:
That 129-byte stub is exactly what
git diff --statreports as the "new" version:Where it came from
9d72a1bb— "chore: add git lfs tracking and update ci workflows" (#1242), 2026-04-13. That commit added the LFS rules but did not convert the files that were already in the repo, and nothing has converted them since.36 files match the LFS rules. Only 2 of them are actually stored in LFS:
apps/dojo/e2e/fixtures/test-image.pngsdks/dotnet/tests/AGUI.Hosting.AspNetCore.IntegrationTests/Samples/GettingStarted/ag-ui-logo.pngThe other 34 are in the mismatched state. In other words, LFS has been switched on for about four months and has been used for two files.
(Only 26 of the 34 showed up in my
git status. Git skips this comparison when a file's timestamp still matches what it recorded at checkout, so the other 8 are quietly in the same state — they just haven't been looked at yet.)Steps to Reproduce
git-lfsinstalled.git status— or touch any tracked image, e.g.touch docs/logo/AG-UI\ logo_dark.png.git show HEAD:"docs/logo/AG-UI logo_dark.png" | shasumandshasum "docs/logo/AG-UI logo_dark.png"return the same hash.Expected Behavior
A clean checkout should report a clean tree. Either the files are stored in LFS and match the rules, or the rules should not claim they are.
Why this is worth fixing rather than ignoring
It is not just noise — it is a footgun:
git add -Aorgit commit -asilently converts images to LFS stubs, mixed into whatever they were actually working on. On a docs-heavy repo where people regularly touch images, that will land eventually. (I scoped a docs commit to two named files today specifically to avoid it — docs(tools): document ToolMessage.error in tool result examples #2311.)git-lfsinstalled get the 129-byte text stub instead of the image, so docs and example apps render broken images with no obvious explanation.git status— the exact habit that lets a real accidental change slip through.Two ways to fix it, and a recommendation
Option A — remove the LFS rules (my recommendation). Delete the LFS block from
.gitattributesand keep binaries as ordinary Git files. Reasons:git-lfsinstalled to see images.Option B — finish the migration. Run
git add --renormalize .and commit, which converts all 34 files to LFS in one go. This gives a consistent state, but it means a 34-file binary commit that every open PR and fork has to rebase through, and it keeps thegit-lfs-required-to-see-images downside.Either option fixes the phantom-modified problem. The important thing is that the rules and the files agree.
Two related things found while looking
Both are independent of the LFS decision:
sdks/community/dart/test/client/config_test.dillis 10.5 MB — a Dart build artifact, and the single largest binary in the repo. It is half of the 20.3 MB total. Build artifacts probably should not be committed at all; this one looks accidental and is a good candidate for deletion plus a.gitignoreentry.docs/videos/Dojo-overview.mp4(3.2 MB) is the one file where LFS would genuinely earn its keep. If there is an appetite to keep LFS for large media only, that is the file to keep it for — but it should then be migrated properly rather than left in today's mismatched state.Environment