{"record":{"id":"5860fe16b79997c6","repo":"gitroomhq/postiz-app","slug":"unauthorized","errorCode":null,"errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"http","errorClass":"HttpException","httpStatus":400,"severity":"error","filePath":"apps/backend/src/api/routes/admin.controller.ts","lineNumber":24,"sourceCode":"} from '@nestjs/common';\nimport { GetUserFromRequest } from '@gitroom/nestjs-libraries/user/user.from.request';\nimport { User } from '@prisma/client';\nimport { ApiTags } from '@nestjs/swagger';\nimport { ErrorsService } from '@gitroom/nestjs-libraries/database/prisma/errors/errors.service';\nimport { AdminStatsService } from '@gitroom/nestjs-libraries/database/prisma/admin-stats/admin-stats.service';\nimport dayjs from 'dayjs';\n\n@ApiTags('Admin')\n@Controller('/admin')\nexport class AdminController {\n  constructor(\n    private _errorsService: ErrorsService,\n    private _adminStatsService: AdminStatsService\n  ) {}\n\n  private assertSuperAdmin(user: User) {\n    if (!user?.isSuperAdmin) {\n      throw new HttpException('Unauthorized', 400);\n    }\n  }\n\n  @Get('/errors')\n  async listErrors(\n    @GetUserFromRequest() user: User,\n    @Query('page') page?: string,\n    @Query('limit') limit?: string,\n    @Query('platform') platform?: string,\n    @Query('email') email?: string,\n    @Query('unknownFirst') unknownFirst?: string\n  ) {\n    this.assertSuperAdmin(user);\n    return this._errorsService.listErrors({\n      page: page ? parseInt(page, 10) : 0,\n      limit: limit ? parseInt(limit, 10) : 20,\n      platform: platform || undefined,\n      email: email || undefined,","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/gitroomhq/postiz-app/blob/0f1647f7491a217d43eb5ae7a480484bdf0aff3e/apps/backend/src/api/routes/admin.controller.ts#L6-L42","documentation":"The admin controller's assertSuperAdmin guard throws HttpException('Unauthorized', 400) when the authenticated user lacks the isSuperAdmin flag. It protects all super-admin-only endpoints (listErrors, listPlatforms, getStats). Note the status code is 400 (Bad Request) even though the message says Unauthorized, which is misleading.","triggerScenarios":"Calling GET /admin/errors, /admin/platforms or /admin/stats with a session/user whose isSuperAdmin property is false or undefined. Happens for regular org users, expired sessions that resolve to a partial user object, or self-hosted instances where no super admin was configured.","commonSituations":"Self-hosting Postiz without setting IS_SUPER_ADMIN for the first user; logging in with a normal account and navigating to admin routes; token from a user record where isSuperAdmin was never set in the database.","solutions":["Verify the user row in the database actually has isSuperAdmin=true (User table) and re-login","For self-hosted setups, set the IS_SUPER_ADMIN env variable to your email/ID before registering so the first user is promoted","If you are the admin but still blocked, clear cookies/session and re-authenticate so GetUserFromRequest resolves the full user","If you maintain the code, consider throwing 401/403 instead of 400 for semantic correctness"],"exampleFix":"// before\nif (!user?.isSuperAdmin) {\n  throw new HttpException('Unauthorized', 400);\n}\n// after\nif (!user?.isSuperAdmin) {\n  throw new HttpException('Unauthorized', HttpStatus.FORBIDDEN);\n}","handlingStrategy":"type-guard","validationCode":"const me = await api.getMe();\nif (!me?.isSuperAdmin) {\n  throw new Error('This action requires a super admin account');\n}","typeGuard":"const isSuperAdmin = (u: User | null | undefined): u is User & { isSuperAdmin: true } =>\n  Boolean(u?.isSuperAdmin);","tryCatchPattern":"try { await adminApi.getStats(); } catch (e) { if (e instanceof HttpException && e.message === 'Unauthorized') showPermissionError(); else throw e; }","preventionTips":["Gate admin UI routes behind an isSuperAdmin check before rendering","Fetch /me on app boot and store the role for route guards","Never cache admin credentials across role downgrades; force re-login"],"tags":["authorization","super-admin","nestjs","admin"],"backgroundTag":"authorization-denied","analyzedSha":"0f1647f7491a217d43eb5ae7a480484bdf0aff3e","analyzedAt":"2026-08-27T12:09:55.020Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}