{"record":{"id":"714aeefd66dfcb47","repo":"nodejs/node","slug":"unknown-positional-argument-extra","errorCode":null,"errorMessage":"Unknown positional argument: ${extra}","messagePattern":"Unknown positional argument: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"deps/npm/lib/base-cmd.js","lineNumber":424,"sourceCode":"        }\n      }\n    }\n\n    // Remove warnings for unknown positionals that were actually consumed as flag values by command-specific definitions (e.g., --id <value> where --id is command-specific)\n    const remainsSet = new Set(remains)\n    for (const unknownPos of this.npm.config.getUnknownPositionals()) {\n      if (!remainsSet.has(unknownPos)) {\n        // This value was consumed as a flag value, not truly a positional\n        this.npm.config.removeUnknownPositional(unknownPos)\n      }\n    }\n\n    // Warn about extra positional arguments beyond what the command expects\n    const expectedPositionals = this.constructor.positionals\n    if (expectedPositionals !== null && remains.length > expectedPositionals) {\n      const extraPositionals = remains.slice(expectedPositionals)\n      for (const extra of extraPositionals) {\n        throw new Error(`Unknown positional argument: ${extra}`)\n      }\n    }\n\n    this.npm.config.logWarnings()\n  }\n\n  async exec () {\n    // This method should be overridden by commands\n    // Subcommand routing is handled in npm.js #exec\n  }\n}\n\nmodule.exports = BaseCommand\n","sourceCodeStart":406,"sourceCodeEnd":438,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/npm/lib/base-cmd.js#L406-L438","documentation":"After option parsing, npm compares leftover positional arguments against the count the command declares (constructor.positionals). Any positional beyond that count is treated as unknown and throws, naming the first extra. This guards against typos and wrong-command usage.","triggerScenarios":"Passing more positional arguments than the command accepts, e.g. a single-positional command given two; values that were meant as flag values but parsed as positionals because the flag was omitted.","commonSituations":"Quoting that splits one arg into many; wrong command chosen for the intent; trailing junk from a variable expansion ($UNSET expanding to nothing or extra tokens).","solutions":["Count your positionals against the command signature in `npm help <command>` and remove the named extra","If an extra was meant as a flag value, attach it with `=` or add the missing flag (e.g. --opt=value)","Quote multi-word single arguments so the shell does not split them"],"exampleFix":"# before\nnpm cache verify /tmp/extra\n\n# after\nnpm cache verify","handlingStrategy":"validation","validationCode":"// Validate positional count against the command's documented arity before running\nfunction validatePositionals(cmd, positionals, expected) {\n  if (expected !== null && positionals.length > expected) {\n    throw new Error(`${cmd} expects at most ${expected} positional(s), got ${positionals.length}`)\n  }\n}","typeGuard":"function withinPositionalLimit(args, limit) {\n  return limit === null || args.length <= limit\n}","tryCatchPattern":null,"preventionTips":["Quote arguments that contain spaces so the shell does not split them","Validate dynamic argv length before invoking npm when args come from variables","Prefer flag=value form to avoid a value being parsed as a positional"],"tags":["cli","arguments","usage","positional"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}