{"record":{"id":"39e92beba29354a8","repo":"semaphoreui/semaphore","slug":"no-rows-in-result-set","errorCode":null,"errorMessage":"no rows in result set","messagePattern":"no rows in result set","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"db/Store.go","lineNumber":158,"sourceCode":"}\n\n// ObjectProps describe database entities.\n// It mainly used for NoSQL implementations (currently BoltDB) to preserve same\n// data structure of different implementations and easy change it if required.\ntype ObjectProps struct {\n\tTableName             string\n\tType                  reflect.Type // to which type the table bust be mapped.\n\tIsGlobal              bool         // doesn't belong to other table, for example to project or user.\n\tReferringColumnSuffix string\n\tPrimaryColumnName     string\n\tSortableColumns       []string\n\tDefaultSortingColumn  string\n\tSortInverted          bool // sort from high to low object ID by default. It is useful for some NoSQL implementations.\n\tOwnerships            []*ObjectProps\n\tSelectColumns         []string\n}\n\nvar ErrNotFound = errors.New(\"no rows in result set\")\nvar ErrInvalidOperation = errors.New(\"invalid operation\")\n\ntype TaskStatUnit string\n\nconst TaskStatUnitDay TaskStatUnit = \"day\"\nconst TaskStatUnitWeek TaskStatUnit = \"week\"\nconst TaskStatUnitMonth TaskStatUnit = \"month\"\n\ntype TaskFilter struct {\n\tStart  *time.Time `json:\"start\"`\n\tEnd    *time.Time `json:\"end\"`\n\tUserID *int       `json:\"user_id\"`\n\tStatus []task_logger.TaskStatus\n}\n\ntype TaskStat struct {\n\tDate          string                         `json:\"date\"`\n\tCountByStatus map[task_logger.TaskStatus]int `json:\"count_by_status\"`","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/db/Store.go#L140-L176","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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","Treat 'already deleted' as success in idempotent delete flows, as api/apps.go does","Verify the identifier exists (or belongs to the current project/environment) before attempting the lookup/delete"],"exampleFix":"// before\nif err := store.DeleteOptions(\"apps.\"+appID); err != nil {\n    helpers.WriteError(w, err, http.StatusInternalServerError)\n}\n// after\nerr := store.DeleteOptions(\"apps.\" + appID)\nif err != nil && !errors.Is(err, db.ErrNotFound) {\n    helpers.WriteError(w, err, http.StatusInternalServerError)\n}","handlingStrategy":"try-catch","validationCode":"exists, err := store.GetApp(tx, appID)\nif err != nil && !errors.Is(err, db.ErrNotFound) {\n    return err\n}\nif exists == nil { /* skip delete or return 404 */ }","typeGuard":null,"tryCatchPattern":"err := store.DeleteOptions(\"apps.\" + appID)\nif err != nil && !errors.Is(err, db.ErrNotFound) {\n    helpers.WriteError(w, err.Error(), http.StatusInternalServerError)\n    return\n}\n// ErrNotFound: treat as already deleted (idempotent success)","preventionTips":["Always compare with errors.Is(err, db.ErrNotFound), never string equality","Treat deletes as idempotent operations","Check entity existence in the UI before offering delete actions"],"tags":["database","not-found","sentinel-error"],"backgroundTag":"record-not-found","analyzedSha":"1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa","analyzedAt":"2026-09-07T11:00:33.293Z","contentChangedAt":"2026-09-07T11:00:33.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}