{"record":{"id":"40250c754106faa1","repo":"abhigyanpatwari/GitNexus","slug":"invalid-duckdb-extension-name-name","errorCode":null,"errorMessage":"Invalid DuckDB extension name: ${name}","messagePattern":"Invalid DuckDB extension name: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/lbug/extension-loader.ts","lineNumber":238,"sourceCode":"  getCapabilities(): ExtensionCapability[] {\n    return Array.from(this.capabilities.values());\n  }\n\n  /**\n   * Ensure an optional extension is loaded on the supplied connection.\n   *\n   * Returns `true` when the extension is usable on `query`, `false` when it\n   * is unavailable. Never throws on install failure — analyze and query\n   * paths are expected to degrade gracefully.\n   */\n  async ensure(\n    query: (sql: string) => Promise<unknown>,\n    name: string,\n    label: string,\n    opts: ExtensionEnsureOptions = {},\n  ): Promise<boolean> {\n    if (!EXTENSION_NAME_PATTERN.test(name)) {\n      throw new Error(`Invalid DuckDB extension name: ${name}`);\n    }\n\n    const policy = opts.policy ?? this.options.policy ?? resolvePolicyFromEnv();\n    const timeoutMs =\n      opts.installTimeoutMs ?? this.options.installTimeoutMs ?? getExtensionInstallTimeoutMs();\n    const warn = this.options.warn ?? ((msg: string) => logger.warn(msg));\n    const quiet = opts.quiet === true;\n\n    if (policy === 'never') {\n      this.markUnavailable(name, label, 'extension install policy is \"never\"', warn, quiet);\n      return false;\n    }\n\n    const loadError = await this.tryLoad(query, name);\n    if (loadError === null) {\n      this.markLoaded(name);\n      return true;\n    }","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/core/lbug/extension-loader.ts#L220-L256","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass the bare identifier matching /^[A-Za-z][A-Za-z0-9_]*$/ (e.g. \"icu\", not \"icu@v1.1\" or \"icu.duckdb_extension.wasm\")","Normalize configured names once at config-load time (strip suffixes/extensions) rather than at each ensure() call site","Add a unit assertion over your extension config so invalid names fail at startup, not during analyze"],"exampleFix":"// before\nawait coordinator.ensure(query, 'full-text', 'full-text-search');\n// after\nawait coordinator.ensure(query, 'fts', 'full-text-search');","handlingStrategy":"validation","validationCode":"const EXTENSION_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_]*$/;\nexport function assertExtensionName(name: string): void {\n  if (!EXTENSION_NAME_PATTERN.test(name)) {\n    throw new TypeError(`Config error: extension \"${name}\" must match /^[A-Za-z][A-Za-z0-9_]*$/`);\n  }\n}\n// call before coordinator.ensure(...)\nassertExtensionName(extName);\nawait coordinator.ensure(query, extName, label, opts);","typeGuard":"function isValidDuckDbExtensionName(name: unknown): name is string {\n  return typeof name === 'string' && /^[A-Za-z][A-Za-z0-9_]*$/.test(name);\n}","tryCatchPattern":"try {\n  await coordinator.ensure(query, name, label);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Invalid DuckDB extension name')) {\n    // programmer/config error: fix the caller and its config source; do not swallow — ensure() otherwise degrades gracefully only for install failures\n  }\n  throw err;\n}","preventionTips":["Remember ensure()'s contract: it returns false (never throws) for install/load failures, but always throws for invalid names — validate names yourself","Normalize names derived from DuckDB docs/catalog URLs (strip .duckdb_extension, @version) at the config boundary"],"tags":["duckdb","extension","validation","ladybugdb","api-contract"],"backgroundTag":"invalid-identifier","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-08-31T04:17:50.494Z"}