affaan-m/ECC · warning · ErrNotFound
resource not found
Error message
resource not found
What it means
A Go sentinel error ErrNotFound = errors.New("resource not found") from the golang-patterns skill. It is the generic 'row/resource does not exist' sentinel for the domain layer, intended to be matched with errors.Is and wrapped with per-call context via fmt.Errorf. Compared to error-handling's variant, the message is the more descriptive "resource not found".
Source
Thrown at skills/golang-patterns/SKILL.md:130
}
```
### Custom Error Types
```go
// Define domain-specific errors
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)
}
// Sentinel errors for common cases
var (
ErrNotFound = errors.New("resource not found")
ErrUnauthorized = errors.New("unauthorized")
ErrInvalidInput = errors.New("invalid input")
)
```
### Error Checking with errors.Is and errors.As
```go
func HandleError(err error) {
// Check for specific error
if errors.Is(err, sql.ErrNoRows) {
log.Println("No records found")
return
}
// Check for error type
var validationErr *ValidationError
if errors.As(err, &validationErr) {View on GitHub (pinned to 01e15490f0)
Solutions
- Wrap with context at every layer: fmt.Errorf("get order %s: %w", id, ErrNotFound) so logs are actionable.
- Map to 404 at the HTTP boundary using errors.Is, never 500.
- Validate id format before querying (return 400 for malformed ids) to keep 404 semantically 'well-formed but absent'.
- Return a generic message to the client; do not confirm which ids exist.
Example fix
// before
var ErrNotFound = errors.New("resource not found")
// after: keep sentinel stable; add typed errors for finer handling
type NotFoundError struct{ Resource, ID string }
func (e *NotFoundError) Error() string { return e.Resource + " " + e.ID + " not found" }
// handlers can now use errors.As(err, &NotFoundError{}) to include the resource name Defensive patterns
Strategy: validation
Validate before calling
if valid, _ := isWellFormedID(id); !valid {
return httpError(400, "invalid id")
}
_, err := repo.FindByID(ctx, id)
if errors.Is(err, ErrNotFound) {
return httpError(404, "not found")
} Type guard
null
Try / catch
null
Prevention
- Wrap with per-call context (entity + id) at every layer.
- Map ErrNotFound to 404 at the handler, never 500.
- Validate id shape before querying.
When it happens
Trigger: Any repository/service lookup that returns no row wraps ErrNotFound. The handler checks errors.Is(err, ErrNotFound) to respond 404. Also used in switch statements branching on errors.Is against sql.ErrNoRows.
Common situations: REST GET /resource/{id} where id does not exist; concurrent delete between read and update; id derived from untrusted input that does not correspond to a real record; pagination cursor pointing past the last page.
Related errors
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/7e4c4733216bec82.
Report an issue: GitHub.