semaphoreui/semaphore · warning

no rows in result set

Error message

no rows in result set

What it means

ErrNotFound is the sentinel error ('no rows in result set') returned by the store layer when a queried/deleted object does not exist. Callers are expected to check with errors.Is and treat it as an expected condition, not a server error.

Solutions

  1. Check errors.Is(err, db.ErrNotFound) and handle it as a benign case (e.g. return 200/404 to the client) instead of a 500
  2. Treat 'already deleted' as success in idempotent delete flows, as api/apps.go does
  3. Verify the identifier exists (or belongs to the current project/environment) before attempting the lookup/delete

Example fix

// before
if err := store.DeleteOptions("apps."+appID); err != nil {
    helpers.WriteError(w, err, http.StatusInternalServerError)
}
// after
err := store.DeleteOptions("apps." + appID)
if err != nil && !errors.Is(err, db.ErrNotFound) {
    helpers.WriteError(w, err, http.StatusInternalServerError)
}
Defensive patterns

Strategy: try-catch

Validate before calling

exists, err := store.GetApp(tx, appID)
if err != nil && !errors.Is(err, db.ErrNotFound) {
    return err
}
if exists == nil { /* skip delete or return 404 */ }

Try / catch

err := store.DeleteOptions("apps." + appID)
if err != nil && !errors.Is(err, db.ErrNotFound) {
    helpers.WriteError(w, err.Error(), http.StatusInternalServerError)
    return
}
// ErrNotFound: treat as already deleted (idempotent success)

Prevention

When it happens

Trigger: Calling deleteApp (api/apps.go:80) for an app ID that no longer exists or was already deleted; login/external-user lookups with unknown identifiers; any store Get/Delete targeting a missing row.

Common situations: Double-delete races (two requests deleting the same app); stale UI deleting an entity removed by someone else; login attempts with wrong usernames; IDs from another environment.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07). Data as JSON: /api/errors/39e92beba29354a8. Report an issue: GitHub.

Appendix: source

Thrown at db/Store.go:158

}

// ObjectProps describe database entities.
// It mainly used for NoSQL implementations (currently BoltDB) to preserve same
// data structure of different implementations and easy change it if required.
type ObjectProps struct {
	TableName             string
	Type                  reflect.Type // to which type the table bust be mapped.
	IsGlobal              bool         // doesn't belong to other table, for example to project or user.
	ReferringColumnSuffix string
	PrimaryColumnName     string
	SortableColumns       []string
	DefaultSortingColumn  string
	SortInverted          bool // sort from high to low object ID by default. It is useful for some NoSQL implementations.
	Ownerships            []*ObjectProps
	SelectColumns         []string
}

var ErrNotFound = errors.New("no rows in result set")
var ErrInvalidOperation = errors.New("invalid operation")

type TaskStatUnit string

const TaskStatUnitDay TaskStatUnit = "day"
const TaskStatUnitWeek TaskStatUnit = "week"
const TaskStatUnitMonth TaskStatUnit = "month"

type TaskFilter struct {
	Start  *time.Time `json:"start"`
	End    *time.Time `json:"end"`
	UserID *int       `json:"user_id"`
	Status []task_logger.TaskStatus
}

type TaskStat struct {
	Date          string                         `json:"date"`
	CountByStatus map[task_logger.TaskStatus]int `json:"count_by_status"`

View on GitHub (pinned to 1774ccb71a)