{"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":280,"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":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/gitnexus/src/cli/analyze-config.ts#L262-L298","documentation":"A string-array config key (currently only `fetchWrappers`) was set to an empty array `[]`. Because each non-string/empty/invalid entry throws earlier in the loop, this branch is reached only when the array is empty — GitNexus treats declaring the key as intent to add wrappers, so an empty list is rejected as a likely leftover or mistake.","triggerScenarios":"Setting { \"fetchWrappers\": [] } in `.gitnexusrc`.","commonSituations":"Removing all custom wrappers but leaving the key behind; a templated/generated config that renders an empty array when no wrappers apply; cleanup that blanked the list instead of deleting the key.","solutions":["Remove the `fetchWrappers` key entirely if you have no wrappers to declare.","Add at least one valid wrapper name (see error 40 for the identifier rules)."],"exampleFix":"// before\n\"fetchWrappers\": []\n// after\n(remove the key)  — or —\n\"fetchWrappers\": [\"client.get\"]","handlingStrategy":"validation","validationCode":"// Drop the key instead of committing an empty array\nif (Array.isArray(cfg.fetchWrappers) && cfg.fetchWrappers.length === 0) {\n  delete cfg.fetchWrappers;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Omit the fetchWrappers key when there are no wrappers rather than setting [].","Treat an empty array as 'remove the key' in any config generator."],"tags":["config","gitnexusrc","validation","fetch-wrappers"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}