nexu-io/open-design · error

connector refresh source requires connector metadata

Error message

connector refresh source requires connector metadata

What it means

Raised by executeRefreshSource() when source.type === 'connector_tool' but source.connector is undefined. Per the LiveArtifactSource contract, a connector_tool source must carry connector metadata (connectorId, toolName, optional accountLabel) so the refresh knows which connector tool to re-execute; the absence means the artifact's data.json is structurally invalid.

Source

Thrown at apps/daemon/src/live-artifacts/refresh-service.ts:87

function isSupportedSource(source: LiveArtifactSource | undefined): source is LiveArtifactSource {
  if (source === undefined) return false;
  return source.type === 'local_file' || source.type === 'daemon_tool' || source.type === 'connector_tool';
}

function hasRefreshPermission(source: LiveArtifactSource): boolean {
  return source.refreshPermission === 'manual_refresh_granted_for_read_only';
}

async function executeRefreshSource(options: {
  projectsRoot: string;
  projectId: string;
  source: LiveArtifactSource;
  signal: AbortSignal;
}): Promise<BoundedJsonObject> {
  const { projectsRoot, projectId, source, signal } = options;
  if (source.type === 'connector_tool') {
    const connector = source.connector;
    if (connector === undefined) throw new Error('connector refresh source requires connector metadata');
    const result = await connectorService.execute(
      {
        connectorId: connector.connectorId,
        toolName: connector.toolName,
        input: source.input,
        ...(connector.accountLabel === undefined ? {} : { expectedAccountLabel: connector.accountLabel }),
      },
      { projectsRoot, projectId, purpose: 'artifact_refresh', signal },
    );
    if (result.output === null || typeof result.output !== 'object' || Array.isArray(result.output)) {
      throw new Error('connector refresh output must be a JSON object');
    }
    return result.output;
  }
  if (source.type !== 'daemon_tool' && source.type !== 'local_file') {
    throw new Error(`refresh source ${source.type} is not supported yet`);
  }
  return executeLocalDaemonRefreshSource({ projectsRoot, projectId, source, signal });

View on GitHub (pinned to 5be4028344)

Solutions

  1. Before refreshing, validate the source: if source.type === 'connector_tool' require source.connector to be present, else mark the artifact non-refreshable.
  2. Re-run the original connector tool to regenerate the artifact with full source metadata.
  3. Add a backfill migration that reconstructs connector metadata from provenance/history for existing artifacts.

Example fix

// before
if (source.type === 'connector_tool') {
  const connector = source.connector;
  if (connector === undefined) throw new Error('connector refresh source requires connector metadata');
}

// after
if (source.type === 'connector_tool' && !source.connector) {
  return { ok: false, reason: 'source_missing_connector_metadata' };
}
if (source.type === 'connector_tool') {
  const connector = source.connector!;
  // ... proceed
}
Defensive patterns

Strategy: type-guard

Validate before calling

import type { LiveArtifactSource } from '@open-design/contracts';

function isRefreshableConnectorSource(source: LiveArtifactSource): boolean {
  return source.type !== 'connector_tool' || source.connector !== undefined;
}

if (!isRefreshableConnectorSource(source)) {
  return { ok: false, reason: 'source_missing_connector_metadata' };
}

Type guard

import type { LiveArtifactSource } from '@open-design/contracts';

function hasConnectorMetadata(source: LiveArtifactSource): source is LiveArtifactSource & { connector: { connectorId: string; toolName: string } } {
  return source.type === 'connector_tool'
    && source.connector !== undefined
    && typeof source.connector.connectorId === 'string'
    && typeof source.connector.toolName === 'string';
}

Try / catch

try {
  return await executeRefreshSource({ projectsRoot, projectId, source, signal });
} catch (err) {
  if (err instanceof Error && err.message === 'connector refresh source requires connector metadata') {
    return { ok: false, reason: 'source_missing_connector_metadata' };
  }
  throw err;
}

Prevention

When it happens

Trigger: Refreshing a live artifact whose stored LiveArtifactSource has type 'connector_tool' but no connector object — e.g. it was created by an older writer, a migration dropped the field, or a tool produced a source JSON missing the connector block.

Common situations: Schema migration that did not backfill connector metadata on existing connector_tool artifacts; a custom tool that wrote data.json without the connector block; partial write interrupted before connector was attached; connector disconnected and its metadata stripped from the source.

Related errors


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