Repository navigation
[Bug] gh gist edit truncates large gist file and risks data loss #11739
Description
Activity
I haven't deeply verified this, but here is some additional context about the likely root cause and related code-paths; as generated by GitHub Codex (GPT-5) when fed this repo + issue:
Summary of findings
-
Symptom recap
- Editing a large single-file gist (~1.6 MB) via
gh gist editresults in only ~900 KiB of content being loaded and then, if saved, would overwrite the gist with the truncated content.
- Editing a large single-file gist (~1.6 MB) via
Relevant code paths
-
Where the gist content is fetched and prepared for editing
-
-
editRunbuilds agistToUpdatestructure by copying the content from the fetched gist into an update payload:-
The gist content used for editing ultimately comes from
gist.Files[filename].Content. SeeeditRunaround:-
Transforming fetched gist to update schema: copies
file.ContentintogistFileToUpdate.Content- Reference:
pkg/cmd/gist/edit/edit.golines ~133–166
- Reference:
-
Selection of file to edit and binary check
- Reference:
pkg/cmd/gist/edit/edit.golines ~243–270
- Reference:
-
Editor invocation uses the in-memory
gistFile.Contentas the initial buffer:- text is set either from stdin, reading a source file, or via the editor helper using
gistFile.Contentas the starting text - Reference:
pkg/cmd/gist/edit/edit.golines ~271–304
- text is set either from stdin, reading a source file, or via the editor helper using
-
-
-
-
-
The API fetch used by
gh gist edit-
editRuncallsshared.GetGist(...)to obtain gist metadata and file contents, then uses those contents for editing. That function is the likely place where file contents are populated and where truncation must be handled. IneditRun:shared.GetGist(client, host, gistID)- Reference:
pkg/cmd/gist/edit/edit.golines ~133–166
-
Why truncation happens
-
Primary cause: not handling API truncation for large gist files
- The GitHub Gists REST API returns, for each file, a
contentstring and atruncatedflag. For sufficiently large files, the API setstruncated: trueand only includes a shortened content preview; the full content must be fetched fromfiles[...].raw_url. - In the current flow,
gh gist editusesshared.GetGistto populateFiles[].Contentand then passes that to the editor unchanged. There is no logic ineditRunto detect/resolve truncated gist content before editing. This explains why a large file appears cut and presents a risk of overwriting with the truncated text when saved.
- The GitHub Gists REST API returns, for each file, a
-
Secondary observation: the 900 KiB boundary
- The measurement of 921,600 bytes (exactly 900 KiB) is a strong indicator that, beyond the API’s own truncation behavior, there may also be an internal limit encountered during editing (e.g., when
$EDITORis a filter likecat). Regardless, the primary correctness issue is that the initial content used for editing is already truncated when fetched.
- The measurement of 921,600 bytes (exactly 900 KiB) is a strong indicator that, beyond the API’s own truncation behavior, there may also be an internal limit encountered during editing (e.g., when
Ideal fix
-
Always edit the full file contents
-
In
shared.GetGist(or specifically within the gist edit command flow before opening the editor), detect truncated file content and fetch the full text fromfiles[...].raw_url.- If you want to minimize network and memory use, do on-demand fetching only for the file selected for editing (not for all files in a multi-file gist).
- After fetching the raw content, populate
gist.Files[filename].Contentwith the full text so the editor opens with the complete data.
-
-
Add guardrails
- If a file reports
truncated: trueorfile.size > len(content), and the raw content fetch fails, show a clear error with guidance (e.g., “File is too large to edit safely. Trygh gist cloneand edit locally.”). - Do not proceed to editing with truncated content.
- If a file reports
-
Tests to prevent regressions
- Unit test: mock
GetGistto return a file withtruncated=trueand araw_url; stub the raw fetch to return >1 MB content; verify edit opens full content and the update payload uses the complete text. - Unit/integration test: simulate an editor that echoes large input (like
cat) and verify no truncation occurs and that the update request body contains the full content. - Test for the guardrail path: simulate truncated content with failing raw fetch and assert a clear, actionable error.
- Unit test: mock
Concrete spots to adjust
-
Ensure
shared.GetGist(in the gist shared package) or thegh gist editflow:- Checks for
truncated(REST) or analogous GraphQL truncation flags, and then followsfiles[...].raw_urlfor the file to be edited before invoking the editor.
- Checks for
-
Review editor invocation in
editRun:-
The code currently uses:
opts.Edit(editorCommand, filename, gistFile.Content, opts.IO)
with
gistFile.Contentas the initial buffer. Ensure that this path uses temp-file editing (so no stdout capture limits apply) before reading the final content back.
-
By addressing the fetch-time truncation,
gh gist editwill reliably load and save the full contents of large gist files and eliminate the risk of silent data loss.
And this additional information RE: the related API docs:
Further API documentation references
-
GitHub Gist REST API
- https://docs.github.com/en/rest/gists/gists#get-a-gist
- Returns gist metadata and file information, including
content,truncated, andraw_urlfields. Thetruncatedboolean indicates whethercontentis incomplete. Iftrue, the full file must be fetched fromraw_url.
- Returns gist metadata and file information, including
- https://docs.github.com/en/rest/gists/gists#get-a-gist
-
GitHub Gist API behavior
- For large files, the REST API sets
truncated: trueand provides only a shortenedcontentpreview. - Full file contents should be fetched via the
raw_urlproperty, which delivers the complete file contents in plain text.
- For large files, the REST API sets
-
Thanks for reporting this bug, @0xdevalias! 🙏
I can confirm there's a bug in the
gistcommand set. There's this booleantruncatedfield in the API response thatghdoes not respect. I think it's probably because the field has been introduced after thegistcommand set was implemented.Notes on the fix
We need to check all gist retrieval endpoints used and respect the
truncatedfield if it's set totrue. Thetruncatedfield is available down to GHES 3.14 which is the minimum supported version. So, we're okay introducing it intogh.We should be careful not to fetch all contents that are marked as
truncated; rather we should only fetch the full content if we actually need the file (like when editing). The URL to fetch the full gist content is available via theraw_urlfield.Reacted by Kynan Ware and Glenn 'devalias' GrantReacted by Glenn 'devalias' Grant- addedpriority-3Affects a small number of users or is largely cosmeticAffects a small number of users or is largely cosmeticgh-gistrelating to the gh gist commandrelating to the gh gist commandhelp wanted candidateIssue may be marked as help-wanted but not yet ready to accept PRIssue may be marked as help-wanted but not yet ready to accept PRand removedneeds-triageneeds to be reviewedneeds to be reviewed
on Sep 15, 2025 I'll post the acceptance criteria for this change in the next comment.
As a hint to anyone who's going to work on this, the problem is rooted at fetching Gists from the API. When there's a large file, the API truncates its content and sets the
truncatedtotruefor that file. Note that, in such cases, further files in the response will have an empty content (again withtruncated: true).So, the fix basically involves two things:
- Adding
truncatedandraw_urlfields to the response type (See below). Note that since this type is used for bothGETandPOSTHTTP requests, it's necessary to addomitemptyto the new fields' JSON tags so that they don't appear inPOSTrequests.
cli/pkg/cmd/gist/shared/shared.go
Lines 21 to 26 in dab285c
type GistFile struct { Filename string `json:"filename,omitempty"` Type string `json:"type,omitempty"` Language string `json:"language,omitempty"` Content string `json:"content"` } - Checking all places where we read file contents from a fetched gist. If the
truncatedfield is set, then we should hit the URL populated inraw_urlfield to get the full content. Needless to say we shouldn't hit the API if we don't really need the content of the file.
Reacted by Glenn 'devalias' Grant- Adding
Tip
On Linux/Unix, a large file can be created with this:
head /dev/urandom -c 2MiB | base64 > large-file.txtAcceptance Criteria
Affected experiences
Given I have a gist with ID
<GIST-ID>that has a large file (>1MB) named<LARGE-FILE>
When I rungh gist view <GIST-ID> --raw --filename <LARGE-FILE>
Then I see the entire content of the file (not truncated)Given I have a gist with ID
<GIST-ID>that has a large file (>1MB) named<LARGE-FILE>
When I rungh gist edit <GIST-ID>and select the<LARGE-FILE>in the prompt
Then I see the entire gist file content in the editorGiven I have a gist with ID
<GIST-ID>that has a large file (>1MB) named<LARGE-FILE>
When I rungh gist edit <GIST-ID>, select the<LARGE-FILE>in the prompt, and add a few chars to the end of the file
Then the gist file is updated successfully (this can be verified by usinggist clone <GIST-ID>)Unaffected experiences
Given I have a gist with ID
<GIST-ID>, and a few large local files named<LARGE-FILE-1>,<LARGE-FILE-2>, and<LARGE-FILE-3>
When I rungh gist edit <GIST-ID> --add <LARGE-FILE-1> gh gist edit <GIST-ID> --add <LARGE-FILE-2> gh gist edit <GIST-ID> --add <LARGE-FILE-3>Then I see all files are correctly added to the gist (this can be verified by using
gist clone <GIST-ID>)Unaffected experiences
Given I have a few large local files named
<LARGE-FILE-1>,<LARGE-FILE-2>, and<LARGE-FILE-3>
When I rungh gist create <LARGE-FILE-1> <LARGE-FILE-2> <LARGE-FILE-3>
Then I see all files are correctly added to the new gist (this can be verified by usinggist clone <GIST-ID>)Reacted by Glenn 'devalias' Grant- addedhelp wantedContributions welcomeContributions welcomeand removedhelp wanted candidateIssue may be marked as help-wanted but not yet ready to accept PRIssue may be marked as help-wanted but not yet ready to accept PR
on Sep 16, 2025 @0xdevalias, since this is a niche case with gists, I put down the A/C for this issue so that external contributors can help with it.
That said, I'm still responsible to provide you with a workaround, as of which I'd recommend you treating gists as ordinary git repositories. For example, to edit a gist file you can do it like this:
gh gist clone <GIST-ID> my-gist cd my-gist echo foo >> existing-file git add existing-file git commit -m 'updated existing file' git push
Of course, you can always use
gh api gistscommands to interact with the API directly, but I wouldn't recommend that due to the complexity around putting together request body data and handling intricate details.Please let me know if the git approach helps with your situation. 🙏
Reacted by Glenn 'devalias' GrantI put down the A/C for this issue so that external contributors can help with it
@babakks Thanks :) Looks like there is already a PR for it:
That said, I'm still responsible to provide you with a workaround, as of which I'd recommend you treating gists as ordinary git repositories.
Please let me know if the git approach helps with your situation.
@babakks 👌🏻 This was the workaround I identified as well, and it worked well enough for me to refactor the impacted gist to separate it into multiple files (rather than trying to embed huge JSON responses inside markdown code blocks in a single file)
Reacted by Babak K. Shandiz
Describe the bug
When editing a large gist (secret, so can't share directly) containing a single
.mdfile (~1.6 MB, ~38,072 lines, ~1.7M bytes), usinggh gist editdoes not load the entire file content. The file is truncated to about 900K bytes (17,000 lines), instead of loading the full content.This presents a risk: If a user edits and saves, the truncated file will overwrite the gist, resulting in data loss.
Affected version
Steps to reproduce the behavior
.mdfile, ~38,000 lines).gh gist edit <gist-id>(with any editor).Expected vs actual behavior
Expected:
gh gist editshould load and allow editing of the entire file, regardless of size, or should display a clear error message if the file is too large to edit safely.Actual:
Logs