cube-js/cube · error
You cannot change security context via __user from ${session
Error message
You cannot change security context via __user from ${session.user} to ${request.meta.changeUser}, because it's not allowed. What it means
When a SQL client sends the special __user meta property (session variable in the SQL query) with a different username, Cube tries to switch the security context to that user. Switching is only allowed for superusers or when the canSwitchSqlUser callback permits it; otherwise the SQL server throws this error naming the originating and requested users.
Source
Thrown at packages/cubejs-api-gateway/src/sql-server.ts:121
const canSwitchSqlUser: CanSwitchSQLUserFn = options.canSwitchSqlUser
|| this.createDefaultCanSwitchSqlUserFn(options);
const contextByRequest = async (request, session) => {
let userForContext = session.user;
let { securityContext } = session;
if (request.meta.changeUser && request.meta.changeUser !== session.user) {
const sqlAuthRequest: SqlAuthServiceAuthenticateRequest = {
protocol: request.meta.protocol,
method: 'password',
};
const canSwitch = session.superuser || await canSwitchSqlUser(session.user, request.meta.changeUser);
if (canSwitch) {
userForContext = request.meta.changeUser;
const current = await checkSqlAuth({ ...request, ...sqlAuthRequest }, userForContext, null);
securityContext = current.securityContext;
} else {
throw new Error(
`You cannot change security context via __user from ${session.user} to ${request.meta.changeUser}, because it's not allowed.`
);
}
}
return this.contextByNativeReq(request, securityContext, request.id);
};
const canSwitchUserForSession = async (session, user) => session.superuser || canSwitchSqlUser(session.user, user);
this.sqlInterfaceInstance = await registerInterface({
gatewayPort: this.gatewayPort,
pgPort: options.pgSqlPort,
contextToApiScopes: async ({ securityContext }) => this.apiGateway.contextToApiScopesFn(
securityContext,
getEnv('defaultApiScope') || await this.apiGateway.contextToApiScopesDefFn()
),
checkAuth: async ({ request, token }) => {
const { securityContext } = await this.apiGateway.checkAuthFn(request, token);View on GitHub (pinned to 7d981676b3)
Solutions
- Configure canSwitchSqlUser in SQLServer options to authorize the specific user switch.
- Connect with the SQL superuser account (sqlSuperUser) when impersonation via __user is required.
- Remove or correct the __user variable in the client's session settings/BI tool configuration so it matches the authenticated user.
Example fix
// before
const server = new SQLServer(apiGateway, { gatewayPort });
// after
const server = new SQLServer(apiGateway, {
gatewayPort,
canSwitchSqlUser: async (fromUser, toUser) => toUser.startsWith('tenant_')
}); Defensive patterns
Strategy: try-catch
Validate before calling
const mayImpersonate = async (session, targetUser) => session.superuser || (typeof canSwitchSqlUser === 'function' && await canSwitchSqlUser(session.user, targetUser)); // check mayImpersonate(session, request.meta.changeUser) before sending __user
Type guard
function requestsImpersonation(msg: { meta?: { changeUser?: string, protocol?: string } }, sessionUser: string): boolean {
return !!msg.meta?.changeUser && msg.meta.changeUser !== sessionUser;
} Try / catch
try {
await runSqlWithImpersonation(query, targetUser);
} catch (e) {
if (e.message.startsWith("You cannot change security context via __user")) {
console.error(`Impersonation from ${session.user} to ${targetUser} denied; connect as superuser or configure canSwitchSqlUser`);
} else throw e;
} Prevention
- Configure canSwitchSqlUser whenever BI tools inject __user variables.
- Use the sqlSuperUser account for impersonating workflows.
- Audit BI tool connection settings for templated __user variables.
- Never rely on __user impersonation with non-superuser accounts unless explicitly allowed.
When it happens
Trigger: A SQL client issues a query whose __user session variable differs from the authenticated SQL user (e.g. `SET __user = 'other'; SELECT ...`) while the authenticated session is not a superuser and no canSwitchSqlUser option authorizes the switch.
Common situations: BI tools configured with a tenant/user template variable that injects __user while connecting as a shared SQL account; developers imitating multi-tenant impersonation without defining canSwitchSqlUser; connecting as a non-superuser account (sqlUser) instead of the superuser (sqlSuperUser) when impersonation is intended.
Related errors
- Incorrect user name "${user}" or password
- maskedMembers cannot be provided in the query
- Unable to decode JWT key
- JWT without kid inside headers
- Unable to verify, JWK with kid: "${decoded.header.kid}" not
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/36819c073da6c079.
Report an issue: GitHub.