calcom/cal.diy · warning · Error
Already installed
Error message
Already installed
What it means
Thrown by the Giphy install handler when a `credential` row of type `giphy_other` already exists for the same owner (user or team). It is a plain `new Error(...)`, so `getServerErrorFromUnknown` routes it through `getHttpStatusCode`, whose switch falls through to the `default` branch because "Already installed" is not a known ErrorCode — yielding HTTP 500, not the 409 Conflict the message implies. The client therefore sees a 500 with body `{ message: "Already installed" }` for an entirely expected duplicate-install condition.
Source
Thrown at packages/app-store/giphy/api/add.ts:34
return res.status(401).json({ message: "You must be logged in to do this" });
}
const userId = req.session.user.id;
const appType = "giphy_other";
const teamId = Number(req.query.teamId);
const credentialOwner = req.query.teamId ? { teamId } : { userId: req.session.user.id };
await throwIfNotHaveAdminAccessToTeam({ teamId: teamId ?? null, userId });
try {
const alreadyInstalled = await prisma.credential.findFirst({
where: {
type: appType,
...credentialOwner,
},
});
if (alreadyInstalled) {
throw new Error("Already installed");
}
const installation = await prisma.credential.create({
data: {
type: appType,
key: {},
...credentialOwner,
appId: "giphy",
},
});
if (!installation) {
throw new Error("Unable to create user credential for giphy");
}
} catch (error: unknown) {
const httpError = getServerErrorFromUnknown(error);
return res.status(httpError.statusCode).json({ message: httpError.message });
}
return res.status(200).json({ url: getInstalledAppPath({ variant: "other", slug: "giphy" }) });View on GitHub (pinned to 176037d0af)
Solutions
- Fix the source: throw `new HttpError({ statusCode: 409, message: "Already installed" })` so the client gets a correct, handlable status instead of a misleading 500.
- Make the client idempotent: query installed apps before calling install and skip when Giphy is already present.
- Debounce/disable the Install button after the first click to prevent double-submit.
- On the client, treat a response whose message is "Already installed" as a no-op success and proceed to the installed-apps view.
Example fix
// before
if (alreadyInstalled) {
throw new Error("Already installed");
}
// after
import { HttpError } from "@calcom/lib/http-error";
if (alreadyInstalled) {
throw new HttpError({ statusCode: 409, message: "Already installed" });
} Defensive patterns
Strategy: validation
Validate before calling
// Before calling the Giphy install endpoint, confirm it isn't already installed
import prisma from "@calcom/prisma";
async function ensureGiphyNotInstalled(owner: { userId: number } | { teamId: number }) {
const existing = await prisma.credential.findFirst({
where: { type: "giphy_other", ...owner },
select: { id: true },
});
return existing === null; // true => safe to install
}
// usage:
if (await ensureGiphyNotInstalled({ userId })) {
await fetch("/api/integrations/giphy/add", { method: "POST" });
} Try / catch
// Treat the (currently 500) 'Already installed' response as a benign no-op
try {
const res = await fetch("/api/integrations/giphy/add", { method: "POST" });
if (!res.ok) throw new Error(await res.text());
} catch (e) {
if (/Already installed/.test(String(e))) {
// already installed — proceed to the installed-apps view
} else {
throw e;
}
} Prevention
- Disable the Install button immediately after the first click to prevent double-submit.
- Query installed apps on page load and hide Install for apps already present.
- Once the source is fixed to 409, branch on status code rather than message text.
When it happens
Trigger: A request to the Giphy install endpoint (`/api/integrations/giphy/add`, with or without `?teamId=`) when `prisma.credential.findFirst` already returns a `giphy_other` credential for that `userId`/`teamId`. Concretely: double-clicking Install, resubmitting after a first successful install, two concurrent requests both passing the `findFirst` check before either `create`s.
Common situations: User clicks Install twice before navigating away; page refresh resubmits the install form; team admin re-installs for a team that already has Giphy; race condition between two near-simultaneous install requests.
Related errors
- Unable to create user credential for giphy
- Missing Giphy api_key
- Stripe app not found
- Default conferencing app '${defaultApp.appSlug}' doesnt exis
- Default conferencing app '${defaultApp.appSlug}' doesnt exis
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/03df1b6331821222.
Report an issue: GitHub.