nexu-io/open-design · error · ConnectorServiceError

CONNECTOR_NOT_FOUND

CONNECTOR_NOT_FOUND

Error message

connector not found

What it means

Thrown by ConnectorService.getConnector() when getDefinition(connectorId) resolves to undefined, i.e. no catalog entry matches the id. It is a ConnectorServiceError with code CONNECTOR_NOT_FOUND and HTTP 404. This is the read path behind the GET connector detail route and the 'od connector get' CLI.

Solutions

  1. List connectors first (listConnectors) and copy the exact id from the catalog.
  2. Pass { refresh: true } to listConnectors to force a Composio catalog refresh, then retry getConnector.
  3. Verify the connector is not disabled/removed upstream in the Composio dashboard.
  4. Normalize the id (trim, lowercase only if the catalog uses lowercase ids) before the call.

Example fix

// before
await connectorService.getConnector('Gihub');  // typo
// throws CONNECTOR_NOT_FOUND

// after
const { connectors } = await connectorService.listConnectors({ refresh: true });
const id = connectors.find((c) => c.name.toLowerCase().includes('github'))?.id;
if (!id) throw new Error('github connector unavailable');
await connectorService.getConnector(id);
Defensive patterns

Strategy: validation

Validate before calling

async function resolveConnectorId(connectorService: ConnectorService, candidate: string): Promise<string | null> {
  const { connectors } = await connectorService.listConnectors();
  const found = connectors.find((c) => c.id === candidate);
  return found ? found.id : null;
}

const id = await resolveConnectorId(connectorService, rawId);
if (!id) throw new Error(`unknown connector: ${rawId}`);
await connectorService.getConnector(id);

Type guard

async function connectorExists(connectorService: ConnectorService, id: string): Promise<boolean> {
  const { connectors } = await connectorService.listConnectors();
  return connectors.some((c) => c.id === id);
}

// if (!(await connectorExists(connectorService, id))) return 'connector not available';

Try / catch

try {
  return await connectorService.getConnector(id);
} catch (error) {
  if (error instanceof ConnectorServiceError && error.code === 'CONNECTOR_NOT_FOUND') {
    await connectorService.listConnectors({ refresh: true });
    return connectorService.getConnector(id); // one retry after refresh
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling getConnector(connectorId) with an id that is not present in the local fast catalog nor returned by Composio after a refresh, e.g. a typo, a stale id from an older catalog, or an id from a different environment.

Common situations: Hard-coded connector id drifted after a catalog refresh; user typed/pasted an id; the Composio catalog failed to load and only the static catalog is available; cross-environment id mismatch (beta vs stable).

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/e8e4d6e66bfd0e39. Report an issue: GitHub.

Appendix: source

Thrown at apps/daemon/src/connectors/service.ts:640

    if (options.refresh) composioConnectorProvider.clearDiscoveryCache();
    const definitions = options.refresh && !options.hydrateTools
      ? await composioConnectorProvider.refreshCatalog(options.signal)
      : options.hydrateTools
        ? await this.listHydratedDefinitions(options.signal)
        : await this.listDefinitions(options.signal);
    return {
      connectors: definitions.map((definition) => this.toDetail(definition)),
      meta: {
        provider: 'composio',
        ...(options.refresh ? { refreshRequested: true } : {}),
      },
    };
  }

  async getConnector(connectorId: string, signal?: AbortSignal): Promise<ConnectorDetail> {
    const definition = await this.getDefinition(connectorId, signal);
    if (!definition) {
      throw new ConnectorServiceError('CONNECTOR_NOT_FOUND', 'connector not found', 404);
    }
    return this.toDetail(definition);
  }

  async getHydratedConnector(connectorId: string, signal?: AbortSignal): Promise<ConnectorDetail> {
    const definition = await this.getHydratedDefinition(connectorId, signal);
    if (!definition) {
      throw new ConnectorServiceError('CONNECTOR_NOT_FOUND', 'connector not found', 404);
    }
    return this.toDetail(definition);
  }

  async getPreviewConnector(connectorId: string, options: { toolsLimit: number; toolsCursor?: string; signal?: AbortSignal }): Promise<ConnectorDetail> {
    const definition = await this.getPreviewDefinition(connectorId, options);
    if (!definition) {
      throw new ConnectorServiceError('CONNECTOR_NOT_FOUND', 'connector not found', 404);
    }
    return this.toDetail(definition);

View on GitHub (pinned to 5be4028344)