go-gorm/gorm · warning

record not found

Error message

record not found

What it means

logger.ErrRecordNotFound is the sentinel error 'record not found' defined in the logger package (mirroring gorm.ErrRecordNotFound). It is returned by First/Take/Last finishers when the query matched zero rows and the Statement has the RecordNotFound condition set. It is not a driver error - GORM synthesizes it after RowsAffected == 0.

Source

Thrown at logger/logger.go:17

// Package logger provides a logger interface and its implementation for GORM.
package logger

import (
	"context"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"gorm.io/gorm/utils"
)

// ErrRecordNotFound record not found error
var ErrRecordNotFound = errors.New("record not found")

// Colors
const (
	Reset       = "\033[0m"
	Red         = "\033[31m"
	Green       = "\033[32m"
	Yellow      = "\033[33m"
	Blue        = "\033[34m"
	Magenta     = "\033[35m"
	Cyan        = "\033[36m"
	White       = "\033[37m"
	BlueBold    = "\033[34;1m"
	MagentaBold = "\033[35;1m"
	RedBold     = "\033[31;1m"
	YellowBold  = "\033[33;1m"
)

// LogLevel log level

View on GitHub (pinned to 1d6ce99528)

Solutions

  1. Treat ErrRecordNotFound as an expected branch: check errors.Is(err, gorm.ErrRecordNotFound) and return a 404/empty result instead of a 500.
  2. Verify the ID/conditions actually match a row (row may be soft-deleted - query with Unscoped if recovery UI needs it).
  3. If an empty result is normal for your flow, use Find(&users) which returns no error for zero rows.
  4. For race-prone reads, wrap the read+act in a transaction or use upsert (clause.OnConflict) instead of read-then-insert.

Example fix

// before
err := db.First(&user, id).Error
if err != nil { return 500 }

// after
err := db.First(&user, id).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
    return ErrNotFound // 404 to caller
}
if err != nil { return err }
Defensive patterns

Strategy: try-catch

Type guard

func isNotFound(err error) bool { return errors.Is(err, gorm.ErrRecordNotFound) }

Try / catch

err := db.First(&user, id).Error
switch {
case err == nil:
case errors.Is(err, gorm.ErrRecordNotFound):
    return ErrNotFound // expected: 404
default:
    return err // unexpected: 500
}

Prevention

When it happens

Trigger: Calling db.First(&user, id), db.Take, or db.Last on a table where no row matches the WHERE clause; also Session with AllowGlobalUpdate off does not matter here - any First-family read returning 0 rows yields this error.

Common situations: Looking up a record by an ID that was deleted or never existed; filtering with conditions that match nothing (typo'd status value, soft-deleted rows hidden by a soft_delete plugin); race where another request deleted the row between check and read; using Find semantics (which do NOT error) vs First semantics (which do) inconsistently.

Related errors


AI-assisted analysis of go-gorm/gorm@1d6ce99528 (2026-08-15). Data as JSON: /api/errors/5b3c097695f5172a. Report an issue: GitHub.