{"record":{"id":"dd39ec63ee032c15","repo":"abhigyanpatwari/GitNexus","slug":"source-must-list-at-least-one-string","errorCode":null,"errorMessage":"${source} must list at least one string.","messagePattern":"(.+?) must list at least one string\\.","errorType":"validation","errorClass":"GitNexusRcError","httpStatus":null,"severity":"error","filePath":"gitnexus/src/cli/analyze-config.ts","lineNumber":270,"sourceCode":"        }\n        const trimmed = item.trim();\n        if (!trimmed) {\n          throw new GitNexusRcError(`${source} entries must not be empty.`);\n        }\n        assertNoHiddenChars(trimmed, source);\n        // Values may be interpolated into a RegExp downstream. Restrict to\n        // identifier / member-access shapes so a config value can never smuggle\n        // regex metacharacters into a consumer.\n        if (!/^[A-Za-z_$][A-Za-z0-9_$.]*$/.test(trimmed)) {\n          throw new GitNexusRcError(\n            `${source} entry \"${trimmed}\" must be an identifier or member name ` +\n              `(letters, digits, _, $, . — e.g. \"client.get\").`,\n          );\n        }\n        names.push(trimmed);\n      }\n      if (names.length === 0) {\n        throw new GitNexusRcError(`${source} must list at least one string.`);\n      }\n      // De-duplicate and cap to a sane bound so a pathological config cannot\n      // blow up the consumer scan's alternation.\n      return Array.from(new Set(names)).slice(0, 100);\n    }\n    case 'numeric-string': {\n      // Mirror Commander's contract: these options reach the existing CLI\n      // validation as strings. Accept a JSON number or a string; normalize to a\n      // string and let the downstream per-flag validation enforce ranges so the\n      // error messages stay in one place.\n      if (typeof value === 'number') {\n        if (!Number.isFinite(value)) {\n          throw new GitNexusRcError(`${source} must be a finite number.`);\n        }\n        return String(value);\n      }\n      if (typeof value === 'string') {\n        const trimmed = value.trim();","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/cli/analyze-config.ts#L252-L288","documentation":"After validating each element, the string-array validator requires at least one surviving name for 'fetchWrappers'. An empty array (or one that is empty after trimming) means the option was configured to do nothing, which GitNexus treats as a config mistake and rejects.","triggerScenarios":"{\"fetchWrappers\": []} at the top level or inside the nested \"analyze\" block; names.length === 0 after the element loop.","commonSituations":"Committing a scaffolded .gitnexusrc with an empty fetchWrappers placeholder; commenting out all entries but leaving \"fetchWrappers\": [] behind; templating systems that render an empty list when a variable is unset.","solutions":["Add at least one valid entry, e.g. {\"fetchWrappers\": [\"client.get\"]}","Or delete the fetchWrappers key entirely — absent is fine, empty is not","Template check: omit the key when the list variable renders empty"],"exampleFix":"// before (.gitnexusrc)\n{\"fetchWrappers\": []}\n// after\n{\"fetchWrappers\": [\"client.get\"]}","handlingStrategy":"validation","validationCode":"if (Array.isArray(rc.fetchWrappers) && rc.fetchWrappers.length === 0) {\n  delete rc.fetchWrappers; // absent is fine, empty is not\n  fs.writeFileSync('.gitnexusrc', JSON.stringify(rc, null, 2));\n}","typeGuard":"const isNonEmptyStringArray = (v: unknown): v is [string, ...string[]] =>\n  Array.isArray(v) && v.length > 0 && v.every((x) => typeof x === 'string');","tryCatchPattern":"catch (err) {\n  if (err instanceof GitNexusRcError && err.message.includes('at least one')) {\n    // either add an entry or drop the key\n  }\n}","preventionTips":["When disabling fetchWrappers, remove the key rather than emptying the array","Template guard: omit keys whose list variables render empty"],"tags":["config","validation","gitnexusrc"],"backgroundTag":"empty-config-value","analyzedSha":"ac9a4e9abd8fd3058c070b72c23402a4f887929a","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}