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 [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/golang-nuts/0AF06538-3EAB-4E89-8F9A-25B7002237B8%40fillmore-labs.com.