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

  1. Fetch a fresh link right before renaming: srcLink, err = d.getLink(ctx, srcLink.LinkID) and retry
  2. If the fresh link still has an empty Hash, recompute it with d.generateNameHash(ctx, currentName, srcLink.ParentLinkID) from the decrypted current name
  3. 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

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.