abhigyanpatwari/GitNexus · error

Invalid DuckDB extension name: ${name}

Error message

Invalid DuckDB extension name: ${name}

What it means

The ExtensionCoordinator.ensure() method in extension-loader.ts runs the same EXTENSION_NAME_PATTERN check (/^[A-Za-z][A-Za-z0-9_]*$/) as the out-of-process installer before doing any load/install work. It is the API every extension consumer (FTS, vector) goes through, so a malformed name fails immediately with this error instead of reaching DuckDB. Unlike install failures — which ensure() swallows and degrades gracefully — an invalid name is a programming/configuration error and always throws.

Source

Thrown at gitnexus/src/core/lbug/extension-loader.ts:238

  getCapabilities(): ExtensionCapability[] {
    return Array.from(this.capabilities.values());
  }

  /**
   * Ensure an optional extension is loaded on the supplied connection.
   *
   * Returns `true` when the extension is usable on `query`, `false` when it
   * is unavailable. Never throws on install failure — analyze and query
   * paths are expected to degrade gracefully.
   */
  async ensure(
    query: (sql: string) => Promise<unknown>,
    name: string,
    label: string,
    opts: ExtensionEnsureOptions = {},
  ): Promise<boolean> {
    if (!EXTENSION_NAME_PATTERN.test(name)) {
      throw new Error(`Invalid DuckDB extension name: ${name}`);
    }

    const policy = opts.policy ?? this.options.policy ?? resolvePolicyFromEnv();
    const timeoutMs =
      opts.installTimeoutMs ?? this.options.installTimeoutMs ?? getExtensionInstallTimeoutMs();
    const warn = this.options.warn ?? ((msg: string) => logger.warn(msg));
    const quiet = opts.quiet === true;

    if (policy === 'never') {
      this.markUnavailable(name, label, 'extension install policy is "never"', warn, quiet);
      return false;
    }

    const loadError = await this.tryLoad(query, name);
    if (loadError === null) {
      this.markLoaded(name);
      return true;
    }

View on GitHub (pinned to aac7515d2a)

Solutions

  1. Pass the bare identifier matching /^[A-Za-z][A-Za-z0-9_]*$/ (e.g. "icu", not "icu@v1.1" or "icu.duckdb_extension.wasm")
  2. Normalize configured names once at config-load time (strip suffixes/extensions) rather than at each ensure() call site
  3. Add a unit assertion over your extension config so invalid names fail at startup, not during analyze

Example fix

// before
await coordinator.ensure(query, 'full-text', 'full-text-search');
// after
await coordinator.ensure(query, 'fts', 'full-text-search');
Defensive patterns

Strategy: validation

Validate before calling

const EXTENSION_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_]*$/;
export function assertExtensionName(name: string): void {
  if (!EXTENSION_NAME_PATTERN.test(name)) {
    throw new TypeError(`Config error: extension "${name}" must match /^[A-Za-z][A-Za-z0-9_]*$/`);
  }
}
// call before coordinator.ensure(...)
assertExtensionName(extName);
await coordinator.ensure(query, extName, label, opts);

Type guard

function isValidDuckDbExtensionName(name: unknown): name is string {
  return typeof name === 'string' && /^[A-Za-z][A-Za-z0-9_]*$/.test(name);
}

Try / catch

try {
  await coordinator.ensure(query, name, label);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Invalid DuckDB extension name')) {
    // programmer/config error: fix the caller and its config source; do not swallow — ensure() otherwise degrades gracefully only for install failures
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling coordinator.ensure(query, 'full-text', 'FTS') or any ensure() whose name argument contains a hyphen, dot, @, or starts with a digit; a config/env-provided extension label that was never normalized.

Common situations: Adding a new optional extension to GitNexus via configuration and pasting the DuckDB catalog filename; sharing config snippets where the extension key drifts from the loadable name; automated config generation adding version suffixes.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20). Data as JSON: /api/errors/40250c754106faa1. Report an issue: GitHub.