RocketChat/Rocket.Chat · error · Meteor.Error

error-application-not-found

error-application-not-found

Error message

Application not found

What it means

deleteOAuthApp calls OAuthApps.findOneAndDeleteById(applicationId) with a clientId projection; when no OAuth app document matches, it throws 'error-application-not-found'. Lookup and delete are atomic, so a concurrent deletion by another admin also surfaces as this error.

Source

Thrown at apps/meteor/server/meteor-methods/auth/deleteOAuthApp.ts:23

import { hasPermissionAsync } from '../../lib/authorization/hasPermission';
import { methodDeprecationLogger } from '../../lib/deprecationWarningLogger';

declare module '@rocket.chat/ddp-client' {
	// eslint-disable-next-line @typescript-eslint/naming-convention
	interface ServerMethods {
		deleteOAuthApp(applicationId: IOAuthApps['_id']): boolean;
	}
}

export const deleteOAuthApp = async (userId: string, applicationId: IOAuthApps['_id']): Promise<boolean> => {
	if (!(await hasPermissionAsync(userId, 'manage-oauth-apps'))) {
		throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'deleteOAuthApp' });
	}

	const application = await OAuthApps.findOneAndDeleteById(applicationId, { projection: { clientId: 1 } });
	if (!application) {
		throw new Meteor.Error('error-application-not-found', 'Application not found', {
			method: 'deleteOAuthApp',
		});
	}

	await OAuthAccessTokens.deleteMany({ clientId: application.clientId });
	await OAuthAuthCodes.deleteMany({ clientId: application.clientId });

	return true;
};

Meteor.methods<ServerMethods>({
	async deleteOAuthApp(applicationId) {
		methodDeprecationLogger.method('deleteOAuthApp', '9.0.0', '/v1/oauth-apps.delete');
		if (!this.userId) {
			throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'deleteOAuthApp' });
		}

		return deleteOAuthApp(this.userId, applicationId);

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Re-fetch the current app list (GET /api/v1/oauth-apps.list) and use the returned _id
  2. Treat 'error-application-not-found' as success in idempotent delete flows — the app is already gone
  3. Validate the id is a well-formed document _id before calling

Example fix

// before — stale id from an old page load
await Meteor.callAsync('deleteOAuthApp', staleAppId);

// after — resolve the id from the live list
const { oauthApps } = await fetch('/api/v1/oauth-apps.list', { headers }).then((r) => r.json());
const app = oauthApps.find((a) => a.name === 'My App');
if (app) await Meteor.callAsync('deleteOAuthApp', app._id);
Defensive patterns

Strategy: validation

Validate before calling

// confirm the app exists with the exact id before deleting
const { oauthApps } = await fetch('/api/v1/oauth-apps.list', { headers }).then((r) => r.json());
const exists = oauthApps.some((a) => a._id === applicationId);
if (!exists) {
  // already deleted: treat as success, skip the call
}

Type guard

const isMeteorErrorCode = (e: unknown, code: string): e is Meteor.Error => e instanceof Meteor.Error && e.error === code;

Try / catch

try {
  await Meteor.callAsync('deleteOAuthApp', applicationId);
} catch (err) {
  if (isMeteorErrorCode(err, 'error-application-not-found')) {
    // idempotent delete: the app is gone — swallow and report success
  }
}

Prevention

When it happens

Trigger: Deleting with a stale or wrong _id; the app was already removed by another tab/admin; the id string is malformed (not a valid document _id).

Common situations: Double-click submitting the delete twice; the UI list is stale because someone else deleted the app; an id copied incompletely out of a URL.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/7d0d1b8d01df5e7d. Report an issue: GitHub.