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
- Verify you are passing the app's configObject id exactly as returned when the app was created/listed.
- Fetch the current app list to obtain a fresh, valid id.
- Check for double-encoding/truncation of the id in your client or proxy.
- 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
- Store ids exactly as returned by the API; never reconstruct them by string concatenation.
- Validate id format client-side before calling app-scoped endpoints.
- Beware double URL-encoding of ids in proxies or query strings.
- Keep the plugin id and the app's configObject id distinct in your client state.
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
- plugin_not_found
- Agent context diagnostics timeout must be between 1 ms and 3
- Invalid cloud provider sync response.
- Invalid cloud provider sync status.
- Invalid cloud provider sync status response.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/59dd005ddb39050a.
Report an issue: GitHub.