mirror of
https://github.com/formbricks/formbricks.git
synced 2026-02-09 18:58:46 -06:00
Compare commits
1 Commits
fix/7190-s
...
fix/not-au
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
deee967511 |
@@ -2,7 +2,7 @@
|
||||
|
||||
import { z } from "zod";
|
||||
import { ZId } from "@formbricks/types/common";
|
||||
import { OperationNotAllowedError } from "@formbricks/types/errors";
|
||||
import { AuthorizationError, OperationNotAllowedError } from "@formbricks/types/errors";
|
||||
import { ZProjectUpdateInput } from "@formbricks/types/project";
|
||||
import { getMembershipByUserIdOrganizationId } from "@/lib/membership/service";
|
||||
import { getOrganization } from "@/lib/organization/service";
|
||||
@@ -138,7 +138,7 @@ export const getProjectsForSwitcherAction = authenticatedActionClient
|
||||
// Need membership for getProjectsByUserId (1 DB query)
|
||||
const membership = await getMembershipByUserIdOrganizationId(ctx.user.id, parsedInput.organizationId);
|
||||
if (!membership) {
|
||||
throw new Error("Membership not found");
|
||||
throw new AuthorizationError("Membership not found");
|
||||
}
|
||||
|
||||
return await getProjectsByUserId(ctx.user.id, membership);
|
||||
|
||||
@@ -8,6 +8,12 @@ import { type ClientErrorType, getClientErrorData } from "@formbricks/types/erro
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { ErrorComponent } from "@/modules/ui/components/error-component";
|
||||
|
||||
/**
|
||||
* Expected error names that should NOT be reported to Sentry.
|
||||
* These are handled gracefully in the UI (e.g., show "no access" or redirect).
|
||||
*/
|
||||
const EXPECTED_ERROR_NAMES = new Set(["AuthorizationError", "AuthenticationError", "TooManyRequestsError"]);
|
||||
|
||||
/**
|
||||
* Get translated error messages based on error type
|
||||
*/
|
||||
@@ -30,10 +36,16 @@ const ErrorBoundary = ({ error, reset }: { error: Error; reset: () => void }) =>
|
||||
const errorData = getClientErrorData(error);
|
||||
const { title, description } = getErrorMessages(errorData.type, t);
|
||||
|
||||
const isExpectedError = EXPECTED_ERROR_NAMES.has(error.name);
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.error(error.message);
|
||||
} else {
|
||||
Sentry.captureException(error);
|
||||
// Only report unexpected errors to Sentry
|
||||
// Expected errors (auth failures, rate limits) are handled gracefully in the UI
|
||||
if (!isExpectedError) {
|
||||
Sentry.captureException(error);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -22,24 +22,29 @@ import { ActionClientCtx } from "./types/context";
|
||||
export const actionClient = createSafeActionClient({
|
||||
handleServerError(e, utils) {
|
||||
const eventId = (utils.ctx as Record<string, any>)?.auditLoggingCtx?.eventId ?? undefined; // keep explicit fallback
|
||||
Sentry.captureException(e, {
|
||||
extra: {
|
||||
eventId,
|
||||
},
|
||||
});
|
||||
|
||||
if (
|
||||
// Expected errors that should NOT be reported to Sentry
|
||||
// These are handled gracefully in the UI (e.g., show "no access", redirect, or retry message)
|
||||
const isExpectedError =
|
||||
e instanceof ResourceNotFoundError ||
|
||||
e instanceof AuthorizationError ||
|
||||
e instanceof InvalidInputError ||
|
||||
e instanceof UnknownError ||
|
||||
e instanceof AuthenticationError ||
|
||||
e instanceof OperationNotAllowedError ||
|
||||
e instanceof TooManyRequestsError
|
||||
) {
|
||||
e instanceof TooManyRequestsError;
|
||||
|
||||
if (isExpectedError) {
|
||||
return e.message;
|
||||
}
|
||||
|
||||
// Only capture unexpected errors to Sentry
|
||||
Sentry.captureException(e, {
|
||||
extra: {
|
||||
eventId,
|
||||
},
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-console -- This error needs to be logged for debugging server-side errors
|
||||
logger.withContext({ eventId }).error(e, "SERVER ERROR");
|
||||
return DEFAULT_SERVER_ERROR_MESSAGE;
|
||||
|
||||
@@ -61,7 +61,7 @@ export const getEnvironmentAuth = reactCache(async (environmentId: string): Prom
|
||||
|
||||
const currentUserMembership = await getMembershipByUserIdOrganizationId(session?.user.id, organization.id);
|
||||
if (!currentUserMembership) {
|
||||
throw new Error(t("common.membership_not_found"));
|
||||
throw new AuthorizationError(t("common.membership_not_found"));
|
||||
}
|
||||
|
||||
const { isMember, isOwner, isManager, isBilling } = getAccessFlags(currentUserMembership?.role);
|
||||
@@ -293,7 +293,7 @@ export const getEnvironmentLayoutData = reactCache(
|
||||
|
||||
// Validate user's membership was found
|
||||
if (!membership) {
|
||||
throw new Error(t("common.membership_not_found"));
|
||||
throw new AuthorizationError(t("common.membership_not_found"));
|
||||
}
|
||||
|
||||
// Fetch remaining data in parallel
|
||||
|
||||
Reference in New Issue
Block a user