@throw inside an @finally block

ID

objectivec.correctness.throw_from_finally

Severity

low

Remediation Complexity

medium

Remediation Risk

medium

Remediation Effort

medium

Resource

Error Handling

Language

Objective-C

Description

Reports a @throw statement inside an @finally block, including one nested in a condition or loop within that block. The region runs from the @finally header to the closing brace at the header’s own indentation, so a @throw in the @try or @catch block, or after the whole statement, is not reported. A return in the same position belongs to the companion rule for returning from a finally block.

Rationale

The @finally block runs while the original exception is still propagating, and throwing from it replaces that exception with this one: the failure that actually happened is lost and the caller diagnoses a cleanup problem instead. Since the cleanup path usually fails only when the original operation did, the exception that surfaces is the least informative of the two.

The following code illustrates the pattern detected by this rule:

@implementation Ledger
- (NSInteger)postAmount:(NSInteger)amount {
    @try {
        return [self commit:amount];
    } @finally {
        // FLAGGED: @throw inside an @finally block
        @throw [NSException exceptionWithName:@"Cleanup" reason:@"unlock failed" userInfo:nil];
    }
}

- (NSInteger)commit:(NSInteger)amount {
    return amount;
}

- (BOOL)unlock {
    return YES;
}

- (void)log:(NSException *)e {
}
@end

Remediation

Handle the cleanup failure inside the @finally block - log it, or record it on the object - rather than throwing out of it, so the exception already in flight reaches the caller. Where the cleanup failure really is the more important one, catch the original exception explicitly and attach it to the new one before throwing.

Configuration

This detector does not need any configuration.

© 2026 Xygeni. All rights reserved