theonedev/onedev · error · RuntimeException

Invalid uploaded content: hash not equals to object id

Error message

Invalid uploaded content: hash not equals to object id

What it means

While handling an LFS object upload, GitLfsFilter computes a hash (e.g. SHA-256) of the streamed body and compares it with the object id the client declared in the LFS API. On mismatch it deletes the stored lfsObject to avoid corrupt data and throws a RuntimeException. This protects the LFS store from incomplete or corrupted uploads.

Source

Thrown at server-core/src/main/java/io/onedev/server/git/GitLfsFilter.java:300

											sha256(), httpRequest.getInputStream())) {
										IOUtils.copy(is, output, BUFFER_SIZE);
										hash.set(Hex.encodeHexString(is.hash().asBytes()));
									} finally {
										output.close();
									}
								};

								try (Response lfsResponse = builder.post(Entity.entity(os, APPLICATION_OCTET_STREAM))) {
									KubernetesHelper.checkStatus(lfsResponse);
								}
							} finally {
								client.close();
							}
						}
					} finally {
						if (!objectId.equals(hash.get())) {
							lfsObject.delete();
							throw new RuntimeException("Invalid uploaded content: hash not equals to object id");
						}
					}
				}
			}									
		} else if (httpRequest.getContentType() != null 
					&& httpRequest.getContentType().startsWith(CONTENT_TYPE)
				|| httpRequest.getHeader("Accept") != null 
					&& httpRequest.getHeader("Accept").startsWith(CONTENT_TYPE)) {
			String projectPath = getProjectPath(pathInfo);
			if (clusterAccess) {
				ProjectFacade project = projectService.findFacadeByPath(projectPath);
				if (project == null) {
					sendBatchError(httpResponse, SC_NOT_FOUND, "Project not found: " + projectPath);
				} else {
					httpResponse.setContentType(CONTENT_TYPE);
					if (pathInfo.endsWith("/batch")) 
						processBatch(httpRequest, httpResponse, project, () -> true, () -> true, clusterService.getCredential());
					else 

View on GitHub (pinned to d44925c47c)

Solutions

  1. Retry: git lfs push --all or git push to re-upload; the corrupt temp object was deleted server-side
  2. Check for proxy/load-balancer request-body size limits or buffering that truncate uploads and raise them
  3. Run git lfs fsck on the client to verify local object integrity, and git lfs fetch --all to repair
  4. Update git-lfs client to a recent version to rule out hashing/upload bugs

Example fix

// before: plain push failing on big file
git push

// after: verify then retry upload with tracing
git lfs fsck
GIT_TRACE=1 GIT_TRANSFER_TRACE=1 git lfs push --all origin
Defensive patterns

Strategy: retry

Validate before calling

// Client-side: verify file hash matches the oid declared in the batch request before upload
const hash = crypto.createHash('sha256').update(fileBuffer).digest('hex');
if (hash !== lfsOid) throw new Error('Local object corrupted; run git lfs fsck');

Try / catch

try {
  await uploadLfsObject(object);
} catch (e) {
  if (e.message.includes('hash not equals to object id')) {
    await gitLfsFsckAndRetry();
  }
}

Prevention

When it happens

Trigger: POST upload to the LFS object endpoint where the digest of received bytes != the oid announced in the LFS batch response; truncated uploads (network drop, proxy buffering limits), client-side file modified between batch negotiation and upload, or wrong oid in the batch request.

Common situations: Unstable network or request body size limits truncating the upload; reverse proxy closing the connection early; a retried upload reusing stale object content; non-LFS-aware proxy altering the body (compression); client LFS version bugs.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/98a34cf891dbb90f. Report an issue: GitHub.