Git push fails for tag names containing + with InvalidObjectIdException in pre-receive callback #3054
sen23 opened 18 hours ago

Environment

  • OneDev version: 15.0.8
  • Git operation: Push a tag to OneDev
  • Affected tag example: 1.0.10+16
  • Branch pushes work normally

Description

Pushing a Git tag whose name contains a + character fails during the server-side pre-receive hook.

For example:

git tag 1.0.10+16
git push origin 1.0.10+16

The client receives:

remote: curl: (22) The requested URL returned error: 500
! [remote rejected] 1.0.10+16 -> 1.0.10+16 (pre-receive hook declined)
error: failed to push some refs

The tag remains local and is not created on the remote repository.

Normal branch pushes to the same repository/server work correctly.

Server-side exception

At the same time, OneDev logs the following exception:

ERROR i.o.s.security.ExceptionHandleFilter - Error processing servlet request

org.eclipse.jgit.errors.InvalidObjectIdException: Invalid id: refs/tags/1.0.10

    at org.eclipse.jgit.lib.ObjectId.fromString(ObjectId.java:203)
    at io.onedev.server.git.hook.GitPreReceiveCallback.doPost(GitPreReceiveCallback.java:119)
    at io.onedev.server.persistence.SessionInterceptor$1.call(SessionInterceptor.java:23)
    at io.onedev.server.persistence.DefaultSessionService.call(DefaultSessionService.java:85)
    at io.onedev.server.persistence.SessionInterceptor.invoke(SessionInterceptor.java:18)
    ...

The interesting part is:

Invalid id: refs/tags/1.0.10

The original tag being pushed is:

refs/tags/1.0.10+16

but the exception only contains:

refs/tags/1.0.10

Steps to reproduce

  1. Create a repository in OneDev 15.0.8.
  2. Clone the repository.
  3. Create a commit if necessary.
  4. Create a tag containing +:
git tag 1.0.10+16
  1. Push the tag:
git push origin 1.0.10+16

Actual result

The push is rejected:

remote: curl: (22) The requested URL returned error: 500
! [remote rejected] 1.0.10+16 -> 1.0.10+16 (pre-receive hook declined)

OneDev logs:

org.eclipse.jgit.errors.InvalidObjectIdException:
Invalid id: refs/tags/1.0.10

from:

io.onedev.server.git.hook.GitPreReceiveCallback.doPost(...)

Expected result

+ is a valid character in a Git ref/tag name.

The following tag should therefore be accepted normally:

refs/tags/1.0.10+16

and the tag should be created on the remote repository.

Suspected cause

This appears to be related to URL/form decoding in the pre-receive hook callback.

The original ref update contains:

refs/tags/1.0.10+16

If the hook sends the ref-update data as application/x-www-form-urlencoded without encoding the literal +, a servlet/form decoder may interpret + as a space:

refs/tags/1.0.10+16

becoming:

refs/tags/1.0.10 16

If OneDev then parses the ref-update record by whitespace, the fields become shifted.

That would explain why:

refs/tags/1.0.10

is eventually passed to:

ObjectId.fromString(...)

and results in:

InvalidObjectIdException: Invalid id: refs/tags/1.0.10

This is only a suspected root cause, but the server-side exception appears consistent with the + character being decoded as whitespace before GitPreReceiveCallback parses the ref update.

  • Branch pushes to the same OneDev server work normally.
  • The failure occurs in the server-side GitPreReceiveCallback.
  • The HTTP 500 is generated by the OneDev callback; it is not a Git authentication or refspec error.
  • The pushed tag is valid according to Git ref naming rules.
  • The original ref contains +16, while the exception shows refs/tags/1.0.10, suggesting the + affects parsing before the object ID conversion.

I checked several existing tag/push-related issues, but they appear to have different root causes:

  • OD-1297 — Pushing tags in CI/CD
  • OD-1409 — Similar client-side curl (22) / pre-receive hook declined symptom, but related to repository/filesystem ownership
  • OD-1585 — Annotated tag handling/fetch issue
  • OD-2359 — Server-side error after pushing a tag related to scheduled builds
  • OD-2729 — Git repository ownership / safe.directory issue

I could not find an existing issue specifically describing a tag/ref containing + causing GitPreReceiveCallback to parse the ref incorrectly.

  • Service Desk commented 18 hours ago

    Your analysis is correct.

    OneDev's git pre-receive / post-receive hook forwards stdin to the server with curl -d @-, which is treated as application/x-www-form-urlencoded. In that encoding, + is decoded as a space.

    So a ref update like:

    <old-oid> <new-oid> refs/tags/1.0.10+16
    

    arrives as:

    <old-oid> <new-oid> refs/tags/1.0.10 16
    

    GitPreReceiveCallback then splits on spaces and passes refs/tags/1.0.10 to ObjectId.fromString(...), which produces exactly the exception you saw:

    InvalidObjectIdException: Invalid id: refs/tags/1.0.10
    

    + is a valid Git ref character, but OneDev currently cannot parse ref updates whose names contain +. The same encoding applies to branch names containing +; typical branch pushes succeed because they do not use that character.

    Until this is fixed, use a tag name without + (for example 1.0.10-16 or 1.0.10_16).

  • Robin Shen commented 17 hours ago

    @servicedesk create a bug report for this and add all users here to watch list

  • Service Desk commented 17 hours ago

    @robin Created bug issue #3055 for this and added @sen23, @robin, and @servicedesk to its watch list.

    Closing this Question.

  • Service Desk changed state to 'Closed' 17 hours ago
    Previous Value Current Value
    Open
    Closed
1/1
Type
Question
Priority
Normal
Assignee
Labels
No labels
Issue Votes (0)
Watchers (3)
Reference
OD-3054
Please wait...
Connection lost or session expired, reload to recover
Page is in error, reload to recover