{"record":{"id":"516e0b23a07bd35e","repo":"multica-ai/multica","slug":"errinstallationnotfound","errorCode":"ErrInstallationNotFound","errorMessage":"lark installation not found","messagePattern":"lark installation not found","errorType":"error_code","errorClass":"lark.ErrInstallationNotFound","httpStatus":404,"severity":"error","filePath":"server/internal/integrations/lark/installation.go","lineNumber":134,"sourceCode":"\t\tif errors.Is(err, pgx.ErrNoRows) {\n\t\t\treturn Installation{}, ErrInstallationNotFound\n\t\t}\n\t\treturn Installation{}, err\n\t}\n\treturn row, nil\n}\n\n// ListByWorkspace returns every installation rooted at the workspace,\n// active and revoked, oldest first. The status column lets the UI\n// distinguish \"wired up\" from \"torn down but kept for audit\".\nfunc (s *InstallationService) ListByWorkspace(ctx context.Context, workspaceID pgtype.UUID) ([]Installation, error) {\n\treturn s.queries.ListLarkInstallationsByWorkspace(ctx, workspaceID)\n}\n\n// ErrInstallationNotFound surfaces \"no row matches in this workspace\"\n// — used by the HTTP layer to return 404. Distinct from a plain\n// pgx.ErrNoRows so handlers do not need to import pgx.\nvar ErrInstallationNotFound = errors.New(\"lark installation not found\")\n\nfunc validateInstallationParams(p InstallationParams) error {\n\tswitch {\n\tcase !p.WorkspaceID.Valid:\n\t\treturn errors.New(\"workspace_id is required\")\n\tcase !p.AgentID.Valid:\n\t\treturn errors.New(\"agent_id is required\")\n\tcase !p.InstallerUserID.Valid:\n\t\treturn errors.New(\"installer_user_id is required\")\n\tcase p.AppID == \"\":\n\t\treturn errors.New(\"app_id is required\")\n\tcase p.AppSecret == \"\":\n\t\treturn errors.New(\"app_secret is required\")\n\tcase p.BotOpenID == \"\":\n\t\treturn errors.New(\"bot_open_id is required\")\n\t}\n\treturn nil\n}","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/integrations/lark/installation.go#L116-L152","documentation":"Lark ErrInstallationNotFound: no lark installation row matches the lookup in the given workspace. It is a distinct sentinel (not raw pgx.ErrNoRows) so HTTP handlers can map it straight to 404 without importing pgx.","triggerScenarios":"Calling InstallationService Get/Revoke-style lookups (e.g. GetLarkInstallationInWorkspace) with a workspace_id + installation_id pair that has no row, or an installation that was revoked/removed. Distinct from ListByWorkspace, which returns both active and revoked installations and never errors on empties.","commonSituations":"Stale URL or cached UI referencing an installation deleted after a workspace re-setup; wrong workspace parameter (installation exists but in another workspace); revoked installation being addressed through a get-by-id path instead of the list view.","solutions":["Re-list installations via ListByWorkspace for the workspace and use the current installation id from that result.","Verify the workspace_id parameter matches the workspace the installation was created in.","If the row was revoked, treat it as gone for actionable paths and re-run the lark install flow to create a new installation."],"exampleFix":"// before\ninst, err := svc.Get(ctx, workspaceID, installationID)\nif err != nil {\n\tlog.Fatal(err) // raw no-rows leaks to caller\n}\n\n// after\ninst, err := svc.Get(ctx, workspaceID, installationID)\nif errors.Is(err, lark.ErrInstallationNotFound) {\n\thttp.NotFound(w, r)\n\treturn\n}","handlingStrategy":"try-catch","validationCode":"insts, err := svc.ListByWorkspace(ctx, workspaceID)\nif err != nil { return err }\nknown := map[pgtype.UUID]bool{}\nfor _, i := range insts { known[i.ID] = true }\nif !known[wantID] {\n\t// refresh UI instead of a doomed get\n\treturn respondList(insts)\n}","typeGuard":null,"tryCatchPattern":"inst, err := svc.Get(ctx, workspaceID, id)\nif err != nil {\n\tif errors.Is(err, lark.ErrInstallationNotFound) {\n\t\thttp.NotFound(w, r) // client refetches the list\n\t\treturn\n\t}\n\treturn err\n}","preventionTips":["Drive installation UIs off ListByWorkspace snapshots rather than cached ids.","Treat 404 on an installation as a signal to refresh, not an error state.","Scope all lookups by workspace_id to avoid cross-workspace id confusion."],"tags":["lark","installation","not-found","integration","go"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}