calcom/cal.diy · warning · Error

Already installed

Error message

Already installed

What it means

Thrown from Alby's 'add' handler when a credential row with the Alby app type already exists for the current user. Alby supports only one credential per user, so re-running the install flow is rejected. The throw is caught by the surrounding try/catch and converted by getServerErrorFromUnknown into the HTTP response.

Source

Thrown at packages/app-store/alby/api/add.ts:21

import { getServerErrorFromUnknown } from "@calcom/lib/server/getServerErrorFromUnknown";
import prisma from "@calcom/prisma";

import config from "../config.json";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (!req.session?.user?.id) {
    return res.status(401).json({ message: "You must be logged in to do this" });
  }
  const appType = config.type;
  try {
    const alreadyInstalled = await prisma.credential.findFirst({
      where: {
        type: appType,
        userId: req.session.user.id,
      },
    });
    if (alreadyInstalled) {
      throw new Error("Already installed");
    }
    const installation = await prisma.credential.create({
      data: {
        type: appType,
        key: {},
        userId: req.session.user.id,
        appId: "alby",
      },
    });

    if (!installation) {
      throw new Error("Unable to create user credential for Alby");
    }
  } catch (error: unknown) {
    const httpError = getServerErrorFromUnknown(error);
    return res.status(httpError.statusCode).json({ message: httpError.message });
  }

View on GitHub (pinned to 176037d0af)

Solutions

  1. Uninstall the existing Alby credential first, then retry the install.
  2. Detect the existing credential on the client and route the user straight to /apps/alby/setup.
  3. In dev, remove the row: prisma.credential.deleteMany({ where: { type: <appType>, userId } }).
  4. Treat the 'Already installed' message in the UI as a redirect, not a hard error.

Example fix

// before
if (alreadyInstalled) {
  throw new Error('Already installed');
}

// after
if (alreadyInstalled) {
  return res.status(200).json({ url: '/apps/alby/setup' });
}
Defensive patterns

Strategy: validation

Validate before calling

const existing = await prisma.credential.findFirst({
  where: { type: appType, userId },
});
if (existing) {
  // route to setup instead of re-running add
}

Type guard

const isAlreadyInstalledError = (e: unknown) =>
  e instanceof Error && e.message === 'Already installed';

Try / catch

try {
  await fetch('/api/integrations/alby/add').then((r) => r.json());
} catch (e) {
  if (isAlreadyInstalledError(e)) {
    router.push('/apps/alby/setup');
  } else throw e;
}

Prevention

When it happens

Trigger: User clicks 'Install Alby' a second time while a credential row already exists; the install flow was interrupted and re-triggered; a previous uninstall left the credential behind.

Common situations: Stale credential after a failed uninstall; dev seed data with a pre-existing alby credential; double-click on the install button; race where two install requests fire concurrently.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/006a36a66d09ff1d. Report an issue: GitHub.