Skip to content

Silent state transition failures due to incorrect MongoDB UpdateOne error handling #79

@jrwbabylonlab

Description

@jrwbabylonlab

The transitionState function in internal/db/delegation.go:59-81 incorrectly assumes MongoDB's UpdateOne() returns mongo.ErrNoDocuments when no document matches the filter. In reality,
UpdateOne() returns success with MatchedCount == 0. The code discards the result and only checks for errors, causing state transitions to report success when no update occurred.

Root Cause:

_, err := client.UpdateOne(ctx, filter, update)  // Result discarded
if err != nil {
    if errors.Is(err, mongo.ErrNoDocuments) {    // Dead code - never true for UpdateOne
        return &NotFoundError{...}
    }
}
return nil  // Returns success even when MatchedCount == 0

Affected Functions:

  • TransitionToUnbondingState
  • TransitionToUnbondedState
  • TransitionToWithdrawnState

Impact:

  • State transitions silently fail when delegation doesn't exist or is in wrong state
  • processExpiredDelegations deletes expire check records even when transitions fail, leaving delegations stuck
  • Unbonding tx data not saved on silent failure of TransitionToUnbondingState

Fix:

Check result.MatchedCount == 0 and return NotFoundError:
result, err := client.UpdateOne(ctx, filter, update)
if err != nil {
    return err
}
if result.MatchedCount == 0 {
    return &NotFoundError{
        Key:     stakingTxHashHex,
        Message: "Delegation not found or not in eligible state to transition",
    }
}
return nil

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions