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

  1. Wrap with context at every layer: fmt.Errorf("get order %s: %w", id, ErrNotFound) so logs are actionable.
  2. Map to 404 at the HTTP boundary using errors.Is, never 500.
  3. Validate id format before querying (return 400 for malformed ids) to keep 404 semantically 'well-formed but absent'.
  4. 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

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.