[GH-ISSUE #5846] [bug]: Cannot create collections or requests in Team Workspaces (Hoppscotch 2026.1.x) #2291

Closed
opened 2026-03-16 23:52:10 +03:00 by kerem · 2 comments
Owner

Originally created by @roopepaajanen on GitHub (Feb 6, 2026).
Original GitHub issue: https://github.com/hoppscotch/hoppscotch/issues/5846

Originally assigned to: @mirarifhasan on GitHub.

Is there an existing issue for this?

  • I have searched existing issues and this bug hasn't been reported yet

Platform

Web App

Browser

Chrome

Operating System

Windows

Bug Description

Version: Hoppscotch 2026.1.x
Deployment: Distributed Kubernetes (self-hosted)
Database: PostgreSQL
Severity: Blocking — team workspaces unusable


Problem

In Hoppscotch 2026.1.x, we cannot create collections or requests in any team workspace.
Only the personal workspace works. All team workspace operations fail.
We can access old requests, send them, modify and save them. Creation of new is only failing


Expected Behavior

Users should be able to create collections and requests in team workspaces.


Actual Behavior

Backend returns errors when creating team collections:

Backend logs
Backend Server | Raw query failed. Code: `42P01`. Message: `relation "TeamCollection" does not exist`
Backend Server |     at /dist/backend/dist/src/team-collection/team-collection.service.js:331:27
Backend Server |     at process.processTicksAndRejections (node:internal/process/task_queues:103:5)
Backend Server |     at async Proxy._transactionWithCallback (/dist/backend/node_modules/.pnpm/@prisma+client@7.2.0_prisma@7.2.0_@types+react@19.2.6_react-dom@19.2.0_react@19.2.0__re_6270a76b5a469f2a05996ebd70951ecb/node_modules/@prisma/client/runtime/client.js:75:4390)
Backend Server |     at async TeamCollectionService.createCollection (/dist/backend/dist/src/team-collection/team-collection.service.js:312:30)
Backend Server |     at async TeamCollectionResolver.createRootCollection (/dist/backend/dist/src/team-collection/team-collection.resolver.js:113:32) {
Backend Server |   response: PrismaClientKnownRequestError: 
Backend Server |   Invalid `prisma.$executeRaw()` invocation:
Backend Server |   
Backend Server |   
Backend Server |   Raw query failed. Code: `42P01`. Message: `relation "TeamCollection" does not exist`
Backend Server |       at qr.handleRequestError (/dist/backend/node_modules/.pnpm/@prisma+client@7.2.0_prisma@7.2.0_@types+react@19.2.6_react-dom@19.2.0_react@19.2.0__re_6270a76b5a469f2a05996ebd70951ecb/node_modules/@prisma/client/runtime/client.js:65:8172)
Backend Server |       at qr.handleAndLogRequestError (/dist/backend/node_modules/.pnpm/@prisma+client@7.2.0_prisma@7.2.0_@types+react@19.2.6_react-dom@19.2.0_react@19.2.0__re_6270a76b5a469f2a05996ebd70951ecb/node_modules/@prisma/client/runtime/client.js:65:7467)
Backend Server |       at qr.request (/dist/backend/node_modules/.pnpm/@prisma+client@7.2.0_prisma@7.2.0_@types+react@19.2.6_react-dom@19.2.0_react@19.2.0__re_6270a76b5a469f2a05996ebd70951ecb/node_modules/@prisma/client/runtime/client.js:65:7174)
Backend Server |       at process.processTicksAndRejections (node:internal/process/task_queues:103:5) {
Backend Server |     code: 'P2010',
Backend Server |     meta: { driverAdapterError: [DriverAdapterError] },
Backend Server |     clientVersion: '7.2.0'
Backend Server |   },
Backend Server |   status: 409,
Backend Server |   options: {}
Backend Server | }
Backend Server | [Nest] 75  - 02/06/2026, 10:09:16 AM   ERROR [ExceptionsHandler] Error: team_coll/creation_failed
Backend Server |     at throwErr (/dist/backend/dist/src/utils.js:68:11)
Backend Server |     at TeamCollectionResolver.createRootCollection (/dist/backend/dist/src/team-collection/team-collection.resolver.js:115:34)
Backend Server |     at process.processTicksAndRejections (node:internal/process/task_queues:103:5)

DB migration

The DB migration is executed succesfully

/dist/backend$ pnpm exec prisma migrate deploy
Loaded Prisma config from prisma.config.ts.

Prisma schema loaded from prisma/schema.prisma.
Datasource "db": PostgreSQL database "dhoppscotch", schema "hps" at "host.net:port"

19 migrations found in prisma/migrations


No pending migrations to apply.
Image

Deployment Type

Self-hosted (on-prem deployment)

Version

2026.1.x

Originally created by @roopepaajanen on GitHub (Feb 6, 2026). Original GitHub issue: https://github.com/hoppscotch/hoppscotch/issues/5846 Originally assigned to: @mirarifhasan on GitHub. ### Is there an existing issue for this? - [x] I have searched existing issues and this bug hasn't been reported yet ### Platform Web App ### Browser Chrome ### Operating System Windows ### Bug Description **Version:** Hoppscotch 2026.1.x **Deployment:** Distributed Kubernetes (self-hosted) **Database:** PostgreSQL **Severity:** Blocking — team workspaces unusable --- ## ❌Problem In Hoppscotch **2026.1.x**, we cannot create **collections or requests in any team workspace**. Only the **personal workspace** works. All team workspace operations fail. We can access old requests, send them, modify and save them. Creation of new is only failing --- ## ✅ Expected Behavior Users should be able to create collections and requests in team workspaces. --- ## ❌ Actual Behavior Backend returns errors when creating team collections: <details> <summary>Backend logs</summary> ``` Backend Server | Raw query failed. Code: `42P01`. Message: `relation "TeamCollection" does not exist` Backend Server | at /dist/backend/dist/src/team-collection/team-collection.service.js:331:27 Backend Server | at process.processTicksAndRejections (node:internal/process/task_queues:103:5) Backend Server | at async Proxy._transactionWithCallback (/dist/backend/node_modules/.pnpm/@prisma+client@7.2.0_prisma@7.2.0_@types+react@19.2.6_react-dom@19.2.0_react@19.2.0__re_6270a76b5a469f2a05996ebd70951ecb/node_modules/@prisma/client/runtime/client.js:75:4390) Backend Server | at async TeamCollectionService.createCollection (/dist/backend/dist/src/team-collection/team-collection.service.js:312:30) Backend Server | at async TeamCollectionResolver.createRootCollection (/dist/backend/dist/src/team-collection/team-collection.resolver.js:113:32) { Backend Server | response: PrismaClientKnownRequestError: Backend Server | Invalid `prisma.$executeRaw()` invocation: Backend Server | Backend Server | Backend Server | Raw query failed. Code: `42P01`. Message: `relation "TeamCollection" does not exist` Backend Server | at qr.handleRequestError (/dist/backend/node_modules/.pnpm/@prisma+client@7.2.0_prisma@7.2.0_@types+react@19.2.6_react-dom@19.2.0_react@19.2.0__re_6270a76b5a469f2a05996ebd70951ecb/node_modules/@prisma/client/runtime/client.js:65:8172) Backend Server | at qr.handleAndLogRequestError (/dist/backend/node_modules/.pnpm/@prisma+client@7.2.0_prisma@7.2.0_@types+react@19.2.6_react-dom@19.2.0_react@19.2.0__re_6270a76b5a469f2a05996ebd70951ecb/node_modules/@prisma/client/runtime/client.js:65:7467) Backend Server | at qr.request (/dist/backend/node_modules/.pnpm/@prisma+client@7.2.0_prisma@7.2.0_@types+react@19.2.6_react-dom@19.2.0_react@19.2.0__re_6270a76b5a469f2a05996ebd70951ecb/node_modules/@prisma/client/runtime/client.js:65:7174) Backend Server | at process.processTicksAndRejections (node:internal/process/task_queues:103:5) { Backend Server | code: 'P2010', Backend Server | meta: { driverAdapterError: [DriverAdapterError] }, Backend Server | clientVersion: '7.2.0' Backend Server | }, Backend Server | status: 409, Backend Server | options: {} Backend Server | } Backend Server | [Nest] 75 - 02/06/2026, 10:09:16 AM ERROR [ExceptionsHandler] Error: team_coll/creation_failed Backend Server | at throwErr (/dist/backend/dist/src/utils.js:68:11) Backend Server | at TeamCollectionResolver.createRootCollection (/dist/backend/dist/src/team-collection/team-collection.resolver.js:115:34) Backend Server | at process.processTicksAndRejections (node:internal/process/task_queues:103:5) ``` </details> ## DB migration The DB migration is executed succesfully ``` /dist/backend$ pnpm exec prisma migrate deploy Loaded Prisma config from prisma.config.ts. Prisma schema loaded from prisma/schema.prisma. Datasource "db": PostgreSQL database "dhoppscotch", schema "hps" at "host.net:port" 19 migrations found in prisma/migrations No pending migrations to apply. ``` <img width="1613" height="480" alt="Image" src="https://github.com/user-attachments/assets/ed63319e-8f1d-484c-abef-48794147e80e" /> ### Deployment Type Self-hosted (on-prem deployment) ### Version 2026.1.x
kerem 2026-03-16 23:52:10 +03:00
Author
Owner

@roopepaajanen commented on GitHub (Feb 6, 2026):

We are running on a light soft fork. Here is the changes we have applied, if it makes a difference in this case.

We authenticate users through proxy (proxyscotch), for the service to be able to access our Microsoft auth process:

microsoft.strategy.js
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? decorators.length : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MicrosoftStrategy = void 0;
const passport_microsoft_1 = require("passport-microsoft");
const passport_1 = require("@nestjs/passport");
const common_1 = require("@nestjs/common");
const auth_service_1 = require("../auth.service");
const user_service_1 = require("../../user/user.service");
const O = require("fp-ts/Option");
const E = require("fp-ts/Either");
const config_1 = require("@nestjs/config");
const utils_1 = require("../../utils");
const errors_1 = require("../../errors");

let HttpsProxyAgent;
try {
    HttpsProxyAgent = require('https-proxy-agent');
} catch (e) {
    console.warn("[MicrosoftStrategy] https-proxy-agent module not found, proxy support disabled.");
    HttpsProxyAgent = null;
}

// ---------- helpers (no new deps) ----------
function maskToken(t) {
    if (!t || typeof t !== "string") return "<empty>";
    if (t.length <= 8) return `${t.slice(0, 2)}${t.slice(-2)} (${t.length})`;
    return `${t.slice(0, 4)}${t.slice(-4)} (${t.length})`;
}
function safeProfileSummary(profile) {
    if (!profile) return { hasProfile: false };
    return {
        hasProfile: true,
        id: profile.id,
        displayName: profile.displayName,
        username: profile.username,
        emailsCount: Array.isArray(profile.emails) ? profile.emails.length : 0,
        email0: Array.isArray(profile.emails) && profile.emails[0] ? profile.emails[0].value : undefined,
        provider: profile.provider,
        _rawPresent: !!profile._raw,
        _jsonPresent: !!profile._json,
    };
}

let MicrosoftStrategy = class MicrosoftStrategy extends (0, passport_1.PassportStrategy)(passport_microsoft_1.Strategy) {
    constructor(authService, usersService, configService) {
        // Proxy config
        const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
        let agent = undefined;
        if (proxyUrl && HttpsProxyAgent) {
            agent = new HttpsProxyAgent(proxyUrl);
        } else if (proxyUrl) {
            console.warn("[MicrosoftStrategy] Proxy URL set but https-proxy-agent not available.");
        } else {
            console.log("[MicrosoftStrategy] No proxy configured.");
        }

        super({
            clientID: configService.get('INFRA.MICROSOFT_CLIENT_ID'),
            clientSecret: configService.get('INFRA.MICROSOFT_CLIENT_SECRET'),
            callbackURL: configService.get('INFRA.MICROSOFT_CALLBACK_URL'),
            scope: configService.get('INFRA.MICROSOFT_SCOPE').split(','),
            tenant: configService.get('INFRA.MICROSOFT_TENANT'),
            store: true,
            proxy: !!proxyUrl,
            agent: agent
        });
        
        if (agent && this._oauth2 && typeof this._oauth2.setAgent === 'function') {
            this._oauth2.setAgent(agent);
            console.log(`[MicrosoftStrategy] Proxy agent set via _oauth2.setAgent`);
        }
        
        this.authService = authService;
        this.usersService = usersService;
        this.configService = configService;
        this.logger = new common_1.Logger(MicrosoftStrategy.name);
    }

    async validate(accessToken, refreshToken, profile, done) {
        const start = Date.now();
        const traceId = Math.random().toString(36).slice(2, 10); // simple local trace id

        try {
            var _a, _b;
            const email = (_b = (_a = profile === null || profile === void 0 ? void 0 : profile.emails) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value;

            if (!(0, utils_1.validateEmail)(email)) {
                console.warn(`[${traceId}] Email missing/invalid from provider profile`);
                throw new common_1.UnauthorizedException(errors_1.AUTH_EMAIL_NOT_PROVIDED_BY_OAUTH);
            }
            const user = await this.usersService.findUserByEmail(email);

            if (O.isNone(user)) {
                const createdUser = await this.usersService.createUserSSO(accessToken, refreshToken, profile);
                return createdUser;
            }

            // Update name/photo if missing
            if (!user.value.displayName || !user.value.photoURL) {
                const updatedUser = await this.usersService.updateUserDetails(user.value, profile);
                if (E.isLeft(updatedUser)) {
                    throw new common_1.UnauthorizedException(updatedUser.left);
                } else {
                }
            } else {
                this.logger.debug(
                    `[${traceId}] User has displayName/photoURL — no details update needed`
                );
            }

            // Provider account link
            const providerAccountExists = await this.authService.checkIfProviderAccountExists(user.value, profile);
            if (O.isNone(providerAccountExists)) {
                await this.usersService.createProviderAccount(user.value, accessToken, refreshToken, profile);
            }

            return user.value;
        } catch (err) {
            // Provide rich context without leaking tokens
            this.logger.error(
                `[${traceId}] validate() failed after ${Date.now() - start}ms — ` +
                `emailFromProfile="${(profile && profile.emails && profile.emails[0] && profile.emails[0].value) || '<none>'}", ` +
                `provider="${(profile && profile.provider) || '<none>'}"`,
                err && err.stack ? err.stack : err
            );
            // Re-throw so Passport/Nest can handle
            throw err;
        } finally {
            this.logger.debug(`[${traceId}] validate() finished in ${Date.now() - start}ms`);
        }
    }
};
exports.MicrosoftStrategy = MicrosoftStrategy;
exports.MicrosoftStrategy = MicrosoftStrategy = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [auth_service_1.AuthService,
        user_service_1.UserService,
        config_1.ConfigService])
], MicrosoftStrategy);

Also, we add the following packages to support our custom config

https-proxy-agent: 5.0.1
debug: 4.3.4
ms: 2.1.3
agent-base: 6.0.2

Here is the paths we use to add these custom modifications

COPY microsoft.strategy.js /dist/backend/dist/src/auth/strategies/microsoft.strategy.js

COPY node_modules/https-proxy-agent /dist/backend/node_modules/https-proxy-agent
COPY node_modules/debug /dist/backend/node_modules/debug
COPY node_modules/ms /dist/backend/node_modules/ms
COPY node_modules/agent-base /dist/backend/node_modules/agent-base
<!-- gh-comment-id:3859629591 --> @roopepaajanen commented on GitHub (Feb 6, 2026): We are running on a light soft fork. Here is the changes we have applied, if it makes a difference in this case. We authenticate users through proxy (proxyscotch), for the service to be able to access our Microsoft auth process: <details> <summary>microsoft.strategy.js</summary> ```js "use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? decorators.length : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MicrosoftStrategy = void 0; const passport_microsoft_1 = require("passport-microsoft"); const passport_1 = require("@nestjs/passport"); const common_1 = require("@nestjs/common"); const auth_service_1 = require("../auth.service"); const user_service_1 = require("../../user/user.service"); const O = require("fp-ts/Option"); const E = require("fp-ts/Either"); const config_1 = require("@nestjs/config"); const utils_1 = require("../../utils"); const errors_1 = require("../../errors"); let HttpsProxyAgent; try { HttpsProxyAgent = require('https-proxy-agent'); } catch (e) { console.warn("[MicrosoftStrategy] https-proxy-agent module not found, proxy support disabled."); HttpsProxyAgent = null; } // ---------- helpers (no new deps) ---------- function maskToken(t) { if (!t || typeof t !== "string") return "<empty>"; if (t.length <= 8) return `${t.slice(0, 2)}…${t.slice(-2)} (${t.length})`; return `${t.slice(0, 4)}…${t.slice(-4)} (${t.length})`; } function safeProfileSummary(profile) { if (!profile) return { hasProfile: false }; return { hasProfile: true, id: profile.id, displayName: profile.displayName, username: profile.username, emailsCount: Array.isArray(profile.emails) ? profile.emails.length : 0, email0: Array.isArray(profile.emails) && profile.emails[0] ? profile.emails[0].value : undefined, provider: profile.provider, _rawPresent: !!profile._raw, _jsonPresent: !!profile._json, }; } let MicrosoftStrategy = class MicrosoftStrategy extends (0, passport_1.PassportStrategy)(passport_microsoft_1.Strategy) { constructor(authService, usersService, configService) { // Proxy config const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY; let agent = undefined; if (proxyUrl && HttpsProxyAgent) { agent = new HttpsProxyAgent(proxyUrl); } else if (proxyUrl) { console.warn("[MicrosoftStrategy] Proxy URL set but https-proxy-agent not available."); } else { console.log("[MicrosoftStrategy] No proxy configured."); } super({ clientID: configService.get('INFRA.MICROSOFT_CLIENT_ID'), clientSecret: configService.get('INFRA.MICROSOFT_CLIENT_SECRET'), callbackURL: configService.get('INFRA.MICROSOFT_CALLBACK_URL'), scope: configService.get('INFRA.MICROSOFT_SCOPE').split(','), tenant: configService.get('INFRA.MICROSOFT_TENANT'), store: true, proxy: !!proxyUrl, agent: agent }); if (agent && this._oauth2 && typeof this._oauth2.setAgent === 'function') { this._oauth2.setAgent(agent); console.log(`[MicrosoftStrategy] Proxy agent set via _oauth2.setAgent`); } this.authService = authService; this.usersService = usersService; this.configService = configService; this.logger = new common_1.Logger(MicrosoftStrategy.name); } async validate(accessToken, refreshToken, profile, done) { const start = Date.now(); const traceId = Math.random().toString(36).slice(2, 10); // simple local trace id try { var _a, _b; const email = (_b = (_a = profile === null || profile === void 0 ? void 0 : profile.emails) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value; if (!(0, utils_1.validateEmail)(email)) { console.warn(`[${traceId}] Email missing/invalid from provider profile`); throw new common_1.UnauthorizedException(errors_1.AUTH_EMAIL_NOT_PROVIDED_BY_OAUTH); } const user = await this.usersService.findUserByEmail(email); if (O.isNone(user)) { const createdUser = await this.usersService.createUserSSO(accessToken, refreshToken, profile); return createdUser; } // Update name/photo if missing if (!user.value.displayName || !user.value.photoURL) { const updatedUser = await this.usersService.updateUserDetails(user.value, profile); if (E.isLeft(updatedUser)) { throw new common_1.UnauthorizedException(updatedUser.left); } else { } } else { this.logger.debug( `[${traceId}] User has displayName/photoURL — no details update needed` ); } // Provider account link const providerAccountExists = await this.authService.checkIfProviderAccountExists(user.value, profile); if (O.isNone(providerAccountExists)) { await this.usersService.createProviderAccount(user.value, accessToken, refreshToken, profile); } return user.value; } catch (err) { // Provide rich context without leaking tokens this.logger.error( `[${traceId}] validate() failed after ${Date.now() - start}ms — ` + `emailFromProfile="${(profile && profile.emails && profile.emails[0] && profile.emails[0].value) || '<none>'}", ` + `provider="${(profile && profile.provider) || '<none>'}"`, err && err.stack ? err.stack : err ); // Re-throw so Passport/Nest can handle throw err; } finally { this.logger.debug(`[${traceId}] validate() finished in ${Date.now() - start}ms`); } } }; exports.MicrosoftStrategy = MicrosoftStrategy; exports.MicrosoftStrategy = MicrosoftStrategy = __decorate([ (0, common_1.Injectable)(), __metadata("design:paramtypes", [auth_service_1.AuthService, user_service_1.UserService, config_1.ConfigService]) ], MicrosoftStrategy); ``` </details> Also, we add the following packages to support our custom config ``` https-proxy-agent: 5.0.1 debug: 4.3.4 ms: 2.1.3 agent-base: 6.0.2 ``` Here is the paths we use to add these custom modifications ``` COPY microsoft.strategy.js /dist/backend/dist/src/auth/strategies/microsoft.strategy.js COPY node_modules/https-proxy-agent /dist/backend/node_modules/https-proxy-agent COPY node_modules/debug /dist/backend/node_modules/debug COPY node_modules/ms /dist/backend/node_modules/ms COPY node_modules/agent-base /dist/backend/node_modules/agent-base ```
Author
Owner

@roopepaajanen commented on GitHub (Feb 6, 2026):

We were able to solve the issue internally by adding more detailed db configurations to our cluster/pod.

<!-- gh-comment-id:3860597823 --> @roopepaajanen commented on GitHub (Feb 6, 2026): We were able to solve the issue internally by adding more detailed db configurations to our cluster/pod.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/hoppscotch#2291
No description provided.