{"record":{"id":"e75b552db836675a","repo":"usememos/memos","slug":"pat-not-found-e75b55","errorCode":null,"errorMessage":"PAT not found","messagePattern":"PAT not found","errorType":"exception","errorClass":null,"httpStatus":401,"severity":"warning","filePath":"store/db/sqlite/user_setting.go","lineNumber":124,"sourceCode":"\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpatsUserSetting := &storepb.PersonalAccessTokensUserSetting{}\n\tif err := protojsonUnmarshaler.Unmarshal([]byte(tokensJSON), patsUserSetting); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, pat := range patsUserSetting.Tokens {\n\t\tif pat.TokenHash == tokenHash {\n\t\t\treturn &store.PATQueryResult{\n\t\t\t\tUserID: userID,\n\t\t\t\tPAT:    pat,\n\t\t\t}, nil\n\t\t}\n\t}\n\n\treturn nil, errors.New(\"PAT not found\")\n}\n","sourceCodeStart":106,"sourceCodeEnd":126,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/store/db/sqlite/user_setting.go#L106-L126","documentation":"The SQLite user_setting driver mirrors the MySQL implementation: load the user's PAT list setting, scan Tokens for TokenHash equality, and return \"PAT not found\" when the loop completes without a match. It is an expected lookup miss, not a database failure.","triggerScenarios":"Valid-format PAT whose hash is not stored for the user — revoked, deleted, or created on a different database file.","commonSituations":"Pointing the instance at a new SQLite file path (fresh DB loses all PATs); deleting a token in the UI while automation still uses it; copying an SQLite DB between environments and using tokens minted elsewhere.","solutions":["Regenerate the PAT against the current database","Verify MEMOS_DATA / DSN points at the SQLite file the token was created in","Handle this error as 401 in callers so clients can re-authenticate"],"exampleFix":"// before (server middleware)\nuser, err := store.FindPAT(ctx, userID, hash)\n// after\nuser, err := store.FindPAT(ctx, userID, hash)\nif err != nil { // includes \"PAT not found\"\n    return echo.NewHTTPError(http.StatusUnauthorized, \"invalid access token\")\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"res, err := d.FindPAT(ctx, userID, tokenHash)\nif err != nil && strings.Contains(err.Error(), \"PAT not found\") {\n    return nil, echo.NewHTTPError(http.StatusUnauthorized, \"invalid access token\")\n}","preventionTips":["Point the instance at the same SQLite file the PAT was created in","Treat PAT-not-found as an auth failure, not a server error"],"tags":["database","sqlite","pat","auth","not-found"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}