Static Analysis for Go Error Type Consistency: errortype Linter

I've been investigating a class of subtle bugs in Go error handling related to 
pointer vs. value semantics with errors.As, and developed a static analysis 
tool to detect these issues. I'm seeking feedback from the community on both 
the approach and the tool's effectiveness.

Problem Statement

Consider this code attempting to handle AES key size errors:

        key := []byte("My kung fu is better than yours")
        _, err := aes.NewCipher(key)

        var kse *aes.KeySizeError
        if errors.As(err, &kse) {
                fmt.Printf("AES keys must be 16, 24 or 32 bytes long, got %d 
bytes.\n", kse)
        } else if err != nil {
                fmt.Println(err)
        }
The bug: aes.NewCipher returns aes.KeySizeError as a value, but the code checks 
for a pointer to *aes.KeySizeError. This type mismatch causes errors.As to fail 
silently, with no compile-time detection.

Analysis and Solution Approach

The core issue is that Go's error interface allows both pointer and value types 
to implement error, but the dynamic type matching in errors.As requires exact 
type correspondence. This creates opportunities for silent failures when the 
expected and actual types don't align.

I propose a two-part mitigation strategy:

1. Compile-time Intent Declaration

Explicit compile-time assertions to document intended usage patterns:

// MyValueError is intended to be used as a value
var _ error = MyValueError{}

// MyPointerError is intended to be used as a pointer
var _ error = (*MyPointerError)(nil)
2. Static Analysis Tool

I've developed errortype, a static analyzer that detects inconsistencies 
between intended error type usage and actual usage patterns. The tool analyzes:

Function return value types
Type assertions and type switches
errors.As target parameters
Method receiver consistency patterns
Example diagnostic output:

main.go:14:20: Target for value error "crypto/aes.KeySizeError" is a 
pointer-to-pointer, use a pointer to a value instead: "var kse 
aes.KeySizeError; ... errors.As(err, &kse)". (et:err)
Request for Feedback

I'm particularly interested in feedback on a few points:

Prevalence: Have you encountered this pointer/value ambiguity with error types? 
How common do you think this class of bug is in practice?

Solution Approach: What are your thoughts on using var _ error = ... assertions 
to declare an error type's intended usage? Is this a practical convention to 
adopt?

Tooling: The detection heuristics are based on these assertions and usage 
pattern analysis. I would be grateful for any real-world testing on your 
codebases to validate their effectiveness and performance.

The tool is currently CLI-only while I refine the detection logic based on 
real-world usage patterns. Integration is planned in a later phase.

References

Detailed analysis: https://blog.fillmore-labs.com/posts/errors-1/
Tool repository: https://github.com/fillmore-labs/errortype
Playground example: https://go.dev/play/p/m4SEPqkZ2Zu
I welcome any insights, particularly from those who have encountered similar 
issues or have thoughts on static analysis approaches for Go error handling 
patterns.

Best regards, Oliver

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/golang-nuts/0AF06538-3EAB-4E89-8F9A-25B7002237B8%40fillmore-labs.com.

Reply via email to