AlistGo/alist · error
failed to get original hash: %w
Error message
failed to get original hash: %w
What it means
Thrown inside the rename flow when d.getOriginalNameHash(srcLink) fails. That helper (util.go:415-425) only fails in two cases: srcLink is nil, or srcLink.Hash is an empty string. Proton Drive requires the link's current name hash in the rename request (OriginalHash), so the operation aborts before the HTTP call.
Source
Thrown at drivers/proton_drive/util.go:604
parentLinkID := srcLink.ParentLinkID
if parentLinkID == "" {
return nil, fmt.Errorf("cannot rename root folder")
}
encryptedName, err := d.encryptFileName(ctx, newName, parentLinkID)
if err != nil {
return nil, fmt.Errorf("failed to encrypt filename: %w", err)
}
newHash, err := d.generateFileNameHash(ctx, newName, parentLinkID)
if err != nil {
return nil, fmt.Errorf("failed to generate new hash: %w", err)
}
originalHash, err := d.getOriginalNameHash(srcLink)
if err != nil {
return nil, fmt.Errorf("failed to get original hash: %w", err)
}
renameReq := RenameRequest{
Name: encryptedName,
NameSignatureEmail: d.MainShare.Creator,
Hash: newHash,
OriginalHash: originalHash,
}
err = d.executeRenameAPI(ctx, srcLink.LinkID, renameReq)
if err != nil {
return nil, fmt.Errorf("rename API call failed: %w", err)
}
return &model.Object{
Name: newName,
Size: srcObj.GetSize(),
Modified: srcObj.ModTime(),View on GitHub (pinned to 843d9dc814)
Solutions
- Fetch a fresh link right before renaming: srcLink, err = d.getLink(ctx, srcLink.LinkID) and retry
- If the fresh link still has an empty Hash, recompute it with d.generateNameHash(ctx, currentName, srcLink.ParentLinkID) from the decrypted current name
- Reject nil srcLink early in the rename entry point with a clear 'source link not found' error
Example fix
// before
originalHash, err := d.getOriginalNameHash(srcLink)
// after
freshLink, err := d.getLink(ctx, srcLink.LinkID)
if err != nil { return nil, fmt.Errorf("failed to refresh link: %w", err) }
originalHash, err := d.getOriginalNameHash(freshLink) Defensive patterns
Strategy: validation
Validate before calling
// before rename:
link, err := d.getLink(ctx, srcLink.LinkID)
if err != nil { return err }
if link == nil || link.Hash == "" {
return fmt.Errorf("source link %s has no name hash; refusing rename", srcLink.LinkID)
} Type guard
func hasNameHash(l *proton.Link) bool { return l != nil && l.Hash != "" } Try / catch
if err := obj.Rename(ctx, obj, newName); err != nil {
if strings.Contains(err.Error(), "failed to get original hash") {
// refresh listing then retry once
}
} Prevention
- Always fetch link metadata via getLink before rename/move, never trust cached link structs
- Refresh the directory listing after any external client has touched the drive
When it happens
Trigger: Calling Rename on a link object whose Hash field was never populated: a link returned by searchByPath/list without hash metadata, a link struct built locally instead of fetched via d.getLink, or a very old Proton item created before name hashing existed.
Common situations: Stale or partially-populated link cache after the item was touched by another client; hand-constructed proton.Link objects; renaming items shared by an account whose keyring/hash key could not be decrypted, leaving Hash empty in the listing.
Related errors
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/44e43f50a0369fc6.
Report an issue: GitHub.