calcom/cal.diy · error · NotFoundException
User with username not found
Error message
User with username ${input.username} not found What it means
A NestJS NotFoundException (HTTP 404) thrown by SlotsInputService_2024_09_04.getEventType when the request resolves an event type by username + event-type slug. The usersRepository.findByUsername(input.username) lookup returned null, so no user matches the supplied username. The error echoes the offending username so you can identify the bad reference.
Solutions
- Verify the username exists in the Cal.com app under /users or via the users API before calling slots.
- Confirm you are passing the `username` field (not email, not display name) and that it matches the user's profile slug exactly (case-sensitive).
- If the user belongs to an organization, pass the correct organizationSlug so the lookup hits the right tenant.
- Catch HTTP 404 in the client and surface a 'user not found' message to the end user with a prompt to re-check the link.
Example fix
// before
const res = await fetch(`/v2/slots?username=${email}&eventTypeSlug=30min`);
// after — use the actual username slug and validate first
const user = await calApi.getUserByUsername(username);
if (!user) throw new ClientError(`Unknown username: ${username}`);
const res = await fetch(`/v2/slots?username=${encodeURIComponent(user.username)}&eventTypeSlug=30min`); Defensive patterns
Strategy: validation
Validate before calling
import { DateTime } from 'luxon';
function assertUsernameResolvable(username: unknown): string {
if (typeof username !== 'string' || username.trim() === '') {
throw new TypeError('username must be a non-empty string');
}
// usernames are slugs — reject emails / display names early
if (/@\s|\s/.test(username)) {
throw new TypeError('Pass the username slug, not an email or display name');
}
return username.trim();
}
// Optional: confirm via GET /v2/users or the app before slots
const username = assertUsernameResolvable(input.username);
const user = await cal.users.getByUsername(username);
if (!user) throw new ClientError(`User '${username}' not found`); Type guard
function isByUsernameAndSlug(value: unknown): value is { username: string; eventTypeSlug: string } {
return typeof value === 'object' && value !== null
&& typeof (value as any).username === 'string'
&& typeof (value as any).eventTypeSlug === 'string';
} Try / catch
try {
await cal.slots.list({ type: 'usernameAndEventTypeSlug', username, eventTypeSlug, start, end });
} catch (e) {
if (e instanceof HttpError && e.statusCode === 404) {
// user does not exist — re-prompt, don't retry blindly
throw new UserFacingError('Booking link is invalid — user not found');
}
throw e;
} Prevention
- Resolve and cache the username from the user API rather than accepting free text.
- Pass organizationSlug when the user belongs to an org.
- URL-encode the username in query strings.
- Treat 404 as terminal for that link — do not auto-retry the same username.
When it happens
Trigger: Calling GET /v2/slots/2024-09-04 with type === "usernameAndEventTypeSlug" where the `username` field does not match any user record (typo, deleted user, unverified account, wrong org scope, or username moved to an organization subdomain).
Common situations: Hardcoding a username in an integration that was later renamed or deleted; passing the user's email instead of their username; querying before the user finished sign-up; username lives under an org slug that was not supplied via organizationSlug.
Related errors
- Team with slug not found
- Event Type with ID= not found
- authenticated user is not owner of event type, does not…
- Booking with id= at has no more seats left.
- Can't reserve a slot if the event is already booked.
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/ec7cf78c08233aeb.
Report an issue: GitHub.
Appendix: source
Thrown at apps/api/v2/src/modules/slots/slots-2024-09-04/services/slots-input.service.ts:102
const baseTransformation = await this.transformGetSlotsQuery(baseQuery);
return {
...baseTransformation,
routedTeamMemberIds: routedTeamMemberIds || null,
skipContactOwner: skipContactOwner || false,
teamMemberEmail: teamMemberEmail || null,
};
}
private async getEventType(input: GetSlotsInput_2024_09_04) {
if (input.type === ById_2024_09_04_type) {
return this.eventTypeRepository.getEventTypeById(input.eventTypeId);
}
if (input.type === ByUsernameAndEventTypeSlug_2024_09_04_type) {
const user = await this.getEventTypeUser(input);
if (!user) {
throw new NotFoundException(`User with username ${input.username} not found`);
}
return this.eventTypeRepository.getUserEventTypeBySlug(user.id, input.eventTypeSlug);
}
if (input.type === ByTeamSlugAndEventTypeSlug_2024_09_04_type) {
const team = await this.getEventTypeTeam(input);
if (!team) {
throw new NotFoundException(`Team with slug ${input.teamSlug} not found`);
}
return this.teamsEventTypesRepository.getEventTypeByTeamIdAndSlug(team.id, input.eventTypeSlug);
}
return input.duration ? { ...dynamicEvent, length: input.duration } : dynamicEvent;
}
private async getEventTypeUser(input: ByUsernameAndEventTypeSlug_2024_09_04) {
return await this.usersRepository.findByUsername(input.username);
}View on GitHub (pinned to 176037d0af)