nexu-io/open-design · error · ConnectorServiceError
CONNECTOR_EXECUTION_FAILED
CONNECTOR_EXECUTION_FAILED
Error message
callbackUrl is required for Composio connectors
What it means
Thrown by ConnectorService.connect() when the resolved definition is Composio-backed (definition.authentication === 'composio'), no credentials were supplied (options.credentials === undefined), and options.callbackUrl is missing. The Composio OAuth redirect flow needs a callback URL to send the user back; without it the daemon cannot start the connection. ConnectorServiceError with code CONNECTOR_EXECUTION_FAILED and HTTP 400.
Source
Thrown at apps/daemon/src/connectors/service.ts:691
return;
}
results[connectorId] = await composioConnectorProvider.prepareAuthConfig(definition, signal);
}));
return { results };
}
async connect(connectorId: string, options: { accountLabel?: string; credentials?: ConnectorCredentialMaterial; callbackUrl?: string; signal?: AbortSignal } = {}): Promise<ConnectorConnectResult> {
const definition = this.getFastDefinition(connectorId) ?? await this.getDefinition(connectorId, options.signal);
if (!definition) {
throw new ConnectorServiceError('CONNECTOR_NOT_FOUND', 'connector not found', 404);
}
let auth: ComposioConnectionStart | undefined;
let detailDefinition = definition;
if (definition.authentication === 'composio' && options.credentials === undefined) {
if (!options.callbackUrl) {
throw new ConnectorServiceError('CONNECTOR_EXECUTION_FAILED', 'callbackUrl is required for Composio connectors', 400, { connectorId });
}
auth = await composioConnectorProvider.connect(definition, options.callbackUrl, options.signal);
if (auth.kind === 'redirect_required' || auth.kind === 'pending') {
return { connector: this.toDetail(detailDefinition), auth: publicComposioAuthStart(auth) };
}
if (auth.credentials !== undefined) {
options = { ...options, ...(auth.accountLabel === undefined ? {} : { accountLabel: auth.accountLabel }), credentials: auth.credentials };
}
}
const status = this.statusService.connect(detailDefinition, options.accountLabel, options.credentials);
if (status.status === 'disabled') {
throw new ConnectorServiceError('CONNECTOR_DISABLED', 'connector is disabled', 403);
}
return { connector: this.toDetail(detailDefinition), ...(auth === undefined ? {} : { auth: publicComposioAuthStart(auth) }) };
}
async disconnect(connectorId: string): Promise<ConnectorDetail> {View on GitHub (pinned to 5be4028344)
Solutions
- Supply options.callbackUrl (a publicly/headlessly reachable URL that completes the OAuth round trip) when calling connect() for a Composio connector.
- If you already hold credentials, pass options.credentials to skip the OAuth redirect path entirely.
- For CLI/headless use, prefer pre-obtained credentials or an out-of-band OAuth flow rather than connect().
Example fix
// before
await connectorService.connect('composio-github', {}); // no callbackUrl, no credentials
// throws "callbackUrl is required for Composio connectors"
// after
await connectorService.connect('composio-github', {
callbackUrl: 'https://app.example.com/api/connectors/callback',
}); Defensive patterns
Strategy: validation
Validate before calling
async function connectComposio(connectorService: ConnectorService, id: string, opts: { callbackUrl?: string; credentials?: Record<string, unknown> }) {
const detail = await connectorService.getConnector(id);
const isComposio = detail.auth?.flow === 'composio'; // or inspect the definition's authentication
if (isComposio && !opts.credentials && !opts.callbackUrl) {
throw new Error('callbackUrl is required to start a Composio OAuth flow');
}
return connectorService.connect(id, opts);
} Type guard
function hasUsableComposioConnectOptions(opts: { callbackUrl?: string; credentials?: unknown }): boolean {
return opts.credentials !== undefined || typeof opts.callbackUrl === 'string' && opts.callbackUrl.length > 0;
}
// if (!hasUsableComposioConnectOptions(opts)) throw new Error('provide callbackUrl or credentials'); Try / catch
try {
return await connectorService.connect(id, opts);
} catch (error) {
if (error instanceof ConnectorServiceError
&& error.code === 'CONNECTOR_EXECUTION_FAILED'
&& /callbackUrl is required/.test(error.message)) {
return { ok: false, reason: 'missing_callback_url' };
}
throw error;
} Prevention
- For Composio OAuth connectors, always provide a reachable callbackUrl (or pre-obtained credentials).
- For headless/CLI use, supply credentials directly to bypass the redirect path.
- Validate callbackUrl reachability before starting the flow.
When it happens
Trigger: Initiating a Composio OAuth connection without supplying credentials and without a callbackUrl, e.g. a CLI/agent call that calls connect() for an OAuth connector but has no HTTP endpoint to receive the redirect.
Common situations: CLI or headless agent tries to start an OAuth flow it cannot complete; the web route forgot to forward its callback URL; migration to a new callback host left the URL empty.
Related errors
- CONNECTOR_EXECUTION_FAILED
- CONNECTOR_OUTPUT_TOO_LARGE
- CONNECTOR_NOT_FOUND
- CONNECTOR_DISABLED
- CONNECTOR_NOT_CONNECTED
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/7985a3f54ffed0fe.
Report an issue: GitHub.