Fix Cursor hooks with corrupted payload content#1443
Open
peckfly wants to merge 1 commit into
Open
Conversation
Member
|
Thank you for the contribution, but isn't this a bug with Cursor? Took a pass through the code -- this is a lot of effort and logic to deal with what is ultimately just bad input. I'm not sure that's the right move. Is there a thread open for this in the Cursor forums? |
|
@peckfly Which version of cursor are you using? |
Contributor
Author
cursor3.5 in windows |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I have only observed this so far when editing large files, roughly over 2,000 lines, on Windows and in Linux SSH remote sessions. I have not been able to reproduce it on macOS. I have not confirmed whether the malformed payload can also be produced in other environments, so the fix is intentionally scoped to handling already-malformed Cursor hook input rather than adding any platform-specific behavior.
Background
Cursor hook payloads can include the full edited file content inside tool_input.content for tools such as Write / Edit. I ran into a case where the payload received by git-ai checkpoint cursor --hook-input stdin was not valid JSON, even though the top-level hook metadata was still present.
The malformed part was inside the tool content string. In that situation, the Cursor preset failed before it could read fields like conversation_id, hook_event_name, tool_name, workspace_roots, and tool_input.file_path, so the checkpoint was skipped entirely with an error similar to:
cursor preset error: Invalid JSON in hook_input: key must be a string ...
This can cause Cursor-originated edits to be missed by git-ai even though the actual file path and hook metadata are still recoverable.
Root Cause
The Cursor preset previously parsed the entire hook payload with strict JSON parsing before extracting any fields. That makes the whole checkpoint depend on tool_input.content being valid JSON-escaped text.
However, for git-ai attribution, the Cursor preset does not need to trust or consume the embedded tool_input.content. The checkpoint flow only needs the hook metadata and edited file path; the actual file contents are read from the working tree later by git-ai.
So if only the large embedded content field is malformed, failing the whole checkpoint loses useful attribution data unnecessarily.
Fix
This PR keeps the existing strict JSON parsing path unchanged for valid Cursor payloads.
If strict parsing fails, it falls back to a narrow Cursor-specific metadata extraction path that only attempts to recover the fields git-ai needs:
conversation_id
hook_event_name
tool_name
workspace_roots
tool_input.file_path / compatible path aliases
optional metadata such as model, tool_use_id, and transcript_path
The fallback intentionally does not parse or use tool_input.content.
If the required metadata cannot be recovered, the preset still returns an error and includes the original JSON parse failure, so this does not silently ignore genuinely unusable payloads.
Why this should be safe
Valid Cursor hook payloads continue to use the original strict JSON parsing behavior.
The lossy fallback is only used after strict parsing fails, and it only reconstructs the small subset of metadata already required by the existing Cursor checkpoint logic. It does not change attribution logic, file diffing, working log generation, or commit note generation.
Testing
Added a regression test with a synthetic corrupted tool_input.content payload. The test verifies that strict JSON parsing fails for the synthetic payload, while the Cursor preset still recovers the required metadata and parses the event as the expected Cursor post-file-edit checkpoint.