diff --git a/.changeset/fix-access-control-silent-error.md b/.changeset/fix-access-control-silent-error.md new file mode 100644 index 00000000000..206a1c1ee32 --- /dev/null +++ b/.changeset/fix-access-control-silent-error.md @@ -0,0 +1,5 @@ +--- +"@keystone-6/core": patch +--- + +Fixed an issue where database errors (connection issues, timeouts, etc.) occurring during unique item existence checks (e.g. in relationship resolvers) were silently swallowed and replaced with a generic "Access denied" error. Unexpected errors are now correctly rethrown to aid debugging. diff --git a/packages/core/src/lib/core/access-control.ts b/packages/core/src/lib/core/access-control.ts index 88a488123c8..10a6448e2df 100644 --- a/packages/core/src/lib/core/access-control.ts +++ b/packages/core/src/lib/core/access-control.ts @@ -17,6 +17,7 @@ import type { ListFilterAccessControl, ListOperationAccessControl, UpdateListItemAccessControl, + DeleteListItemAccessControl, } from '../../types' import { coerceAndValidateForGraphQLInput } from '../coerceAndValidateForGraphQLInput' import { accessDeniedError, accessReturnError, extensionError, formatKeys } from './graphql-errors' @@ -428,7 +429,15 @@ export async function checkUniqueItemExists( try { const item = await context.db[foreignList.listKey].findOne({ where: uniqueInput }) if (item !== null) return uniqueWhere - } catch (err) {} + } catch (err: any) { + // If it's an access denied error from context.db, we swallow it and throw our own + // to keep the error message consistent with "item may not exist". + // But if it's a real database error (e.g. connection, timeout, malformed query), + // we MUST rethrow it so the developer knows what happened. + if (err?.extensions?.code !== 'KS_ACCESS_DENIED') { + throw err + } + } throw accessDeniedError(cannotForItem(operation, foreignList)) }