different-ai/openwork · error · RemoteMcpAppError

remote_app_not_found

remote_app_not_found

Error message

Remote MCP App not found.

What it means

getAppRow first normalizes the incoming configObjectId into a DenTypeId<"configObject">. If the identifier is not a valid den configObject id (normalizeDenTypeId throws), the error is swallowed and a 404 remote_app_not_found is thrown, deliberately not leaking id-format validation details.

Source

Thrown at ee/apps/den-api/src/remote-mcp-apps.ts:359

  }
  const metadata = remoteMcpAppDocumentMetadataSchema.safeParse(value.metadata)
  const source = isRecord(value.source) ? value.source : null
  const resource = isRecord(value.resource) ? value.resource : null
  if (!metadata.success || !source || !resource
    || typeof source.url !== "string" || typeof source.resolvedUrl !== "string" || typeof source.fetchedAt !== "string"
    || (source.contentType !== null && typeof source.contentType !== "string")
    || typeof resource.byteSize !== "number" || typeof resource.digest !== "string") {
    throw new RemoteMcpAppError(422, "invalid_cached_app", "The cached app revision metadata is invalid.")
  }
  return value as RemoteMcpAppVersionPayload
}

async function getAppRow(context: PluginArchActorContext, configObjectId: string, role: "viewer" | "editor" | "manager" = "viewer") {
  let id: DenTypeId<"configObject">
  try {
    id = normalizeDenTypeId("configObject", configObjectId)
  } catch {
    throw new RemoteMcpAppError(404, "remote_app_not_found", "Remote MCP App not found.")
  }
  const rows = await db
    .select()
    .from(RemoteMcpAppTable)
    .where(and(eq(RemoteMcpAppTable.organizationId, context.organizationContext.organization.id), eq(RemoteMcpAppTable.configObjectId, id)))
    .limit(1)
  const app = rows[0]
  if (!app) throw new RemoteMcpAppError(404, "remote_app_not_found", "Remote MCP App not found.")
  await requirePluginArchResourceRole({ context, resourceId: app.configObjectId, resourceKind: "config_object", role })
  return app
}

function serializeRevision(row: RemoteMcpAppVersionRow, activeVersionId: string | null) {
  const payload = parseVersionPayload(row)
  return {
    id: row.id,
    active: row.id === activeVersionId,
    createdAt: row.createdAt.toISOString(),

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Verify you are passing the app's configObject id exactly as returned when the app was created/listed.
  2. Fetch the current app list to obtain a fresh, valid id.
  3. Check for double-encoding/truncation of the id in your client or proxy.
  4. Ensure you are not passing a plugin id where the remote MCP app's configObject id is required.
Defensive patterns

Strategy: validation

Validate before calling

import { normalizeDenTypeId } from "./ids.js";
try { normalizeDenTypeId("configObject", configObjectId); }
catch { throw new Error("Invalid configObject id before calling the API"); }

Type guard

function isConfigObjectId(id: string): boolean {
  try { normalizeDenTypeId("configObject", id); return true; } catch { return false; }
}

Try / catch

try {
  const app = await getRemoteMcpApp(context, configObjectId);
} catch (e) {
  if (e instanceof RemoteMcpAppError && e.code === "remote_app_not_found") {
    // id was malformed or the app does not exist; refresh from the app list
  } else throw e;
}

Prevention

When it happens

Trigger: Calling any app-scoped API (app, restored, etc.) with a configObjectId that is not a syntactically valid den configObject id — malformed id, wrong id type (e.g. a plugin id passed where a configObject id is expected), or empty/URL-decoded incorrectly.

Common situations: Client caching stale or truncated ids; passing a plugin id instead of the app's configObject id; ids mangled by string concatenation in scripts or by double URL-encoding in a proxy.

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 different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/59dd005ddb39050a. Report an issue: GitHub.