{"record":{"id":"aa8daf4640d1e61d","repo":"abhigyanpatwari/GitNexus","slug":"invalid-duckdb-extension-name-extensionname","errorCode":null,"errorMessage":"Invalid DuckDB extension name: ${extensionName}","messagePattern":"Invalid DuckDB extension name: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/lbug/extension-loader.ts","lineNumber":135,"sourceCode":"  const childScript = new URL('../../../scripts/install-duckdb-extension.mjs', import.meta.url);\n  return [fileURLToPath(childScript), extensionName, String(maxDbSize)];\n};\n\n/**\n * Run `INSTALL <extension>` in a short-lived child Node process so the parent\n * event loop is never blocked by DuckDB's synchronous network call.\n *\n * The child opens its own scratch LadybugDB, executes the install, and exits.\n * If the child exceeds `timeoutMs` the parent kills it with SIGKILL and\n * resolves with `timedOut: true`.\n */\nexport const installDuckDbExtensionOutOfProcess = async (\n  extensionName: string,\n  timeoutMs: number = getExtensionInstallTimeoutMs(),\n  loadError?: string,\n): Promise<ExtensionInstallResult> => {\n  if (!EXTENSION_NAME_PATTERN.test(extensionName)) {\n    throw new Error(`Invalid DuckDB extension name: ${extensionName}`);\n  }\n\n  return await new Promise<ExtensionInstallResult>((resolve) => {\n    const child = spawn(process.execPath, getExtensionInstallChildProcessArgs(extensionName), {\n      env: {\n        ...process.env,\n        GITNEXUS_LBUG_EXTENSION_NAME: extensionName,\n        // The child picks INSTALL vs FORCE INSTALL from this LOAD error so it\n        // only re-downloads when the on-disk extension file is actually broken.\n        ...(loadError ? { GITNEXUS_LBUG_EXTENSION_LOAD_ERROR: loadError } : {}),\n      },\n      stdio: ['ignore', 'ignore', 'pipe'],\n      windowsHide: true,\n    });\n\n    let stderr = '';\n    child.stderr?.setEncoding('utf8');\n    child.stderr?.on('data', (chunk) => {","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/core/lbug/extension-loader.ts#L117-L153","documentation":"installDuckDbExtensionOutOfProcess() in gitnexus/src/core/lbug/extension-loader.ts validates the extension name against /^[A-Za-z][A-Za-z0-9_]*$/ before spawning the child process that runs the DuckDB INSTALL. The guard keeps arbitrary strings out of the child's environment and the INSTALL statement (injection safety). Names must start with a letter and contain only letters, digits, and underscores — no hyphens, dots, version suffixes, or file extensions.","triggerScenarios":"Requesting an out-of-process install of a name like \"full-text\" (hyphen), \"icu.duckdb_extension\", \"fts@v1.1.0\", \"42fts\" (leading digit), or an empty string — typically from a lbug extensions config entry or env override that copied the DuckDB catalog name verbatim.","commonSituations":"Copying extension identifiers from DuckDB documentation or marketplace URLs (which include version suffixes and file names); config drift after renaming an internal extension; hand-edited settings files.","solutions":["Use the bare extension identifier: letters/digits/underscore only, starting with a letter (e.g. \"icu\", \"fts\", \"parquet\")","Strip version suffixes (@vX.Y.Z) and file extensions (.duckdb_extension, .wasm) from configured names","Fix the offending entry in the extension configuration that feeds installDuckDbExtensionOutOfProcess"],"exampleFix":"# before\nGITNEXUS_LBUG_EXTENSION_NAME=\"icu.duckdb_extension\"\n# after\nGITNEXUS_LBUG_EXTENSION_NAME=\"icu\"","handlingStrategy":"validation","validationCode":"const EXTENSION_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_]*$/;\nconst name = rawName.trim().replace(/\\.duckdb_extension(\\.wasm)?$/, '').split('@')[0];\nif (!EXTENSION_NAME_PATTERN.test(name)) {\n  throw new TypeError(`Unsupported extension name: ${rawName} (normalized: ${name})`);\n}\nawait installDuckDbExtensionOutOfProcess(name);","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 installDuckDbExtensionOutOfProcess(name, timeoutMs);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Invalid DuckDB extension name')) {\n    // fix the configured name (strip suffixes/hyphens); this is deterministic, never retry as-is\n  }\n  throw err;\n}","preventionTips":["Validate extension names once where they are configured (load-time assert), not at install time","Keep a curated list of known-good extension identifiers and reject anything outside it in config validation"],"tags":["duckdb","extension","validation","injection-guard","ladybugdb"],"backgroundTag":"invalid-identifier","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-08-31T04:17:50.494Z"}