JuliusBrussee/caveman · error

duplicate

Error message

duplicate %s

What it means

parseStatsReportOptions (proxy/cmd/caveman-proxy/stats.go:24) parses the flags for the stats report command and enforces that each option appears at most once, tracking them in a seen map. Repeating any recognized or unrecognized option — even with the same value — is rejected as 'duplicate <arg>'. This keeps the report configuration unambiguous.

Solutions

  1. Remove the duplicated flag, keeping a single occurrence with the desired value
  2. Audit wrapper scripts/aliases that may inject the same flag the user also supplies
  3. Remember the rule applies to every option string, including boolean --report/--json

Example fix

// before
caveman-proxy stats --days 7 --days 30 --report
// after
caveman-proxy stats --days 30 --report
Defensive patterns

Strategy: validation

Validate before calling

function assertNoDuplicateFlags(args) {
  const seen = new Set();
  for (const a of args.filter(x => x.startsWith("--"))) {
    if (seen.has(a)) throw new Error(`duplicate flag ${a}`);
    seen.add(a);
  }
}

Prevention

When it happens

Trigger: Running the stats command with the same flag twice, e.g. 'stats --days 7 --days 30' or '--report --report'. The second occurrence hits seen[arg]==true and returns this error.

Common situations: Shell scripts appending flags conditionally and repeating one; copy-pasting a command line where a flag was already present; aliases or wrappers that inject default flags the user also typed.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/f592d1f438ff811e. Report an issue: GitHub.

Appendix: source

Thrown at proxy/cmd/caveman-proxy/stats.go:24

	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/JuliusBrussee/caveman/proxy/internal/store"
)

// The richer report is explicitly selected. Existing stats --json callers
// (telemetry and session footers) keep their original schema and behavior.
func parseStatsReportOptions(args []string) (store.StatsReportOptions, bool, string, error) {
	opts := store.StatsReportOptions{Days: 30, Now: time.Now()}
	writeReport, out := false, ""
	seen := map[string]bool{}
	for i := 0; i < len(args); i++ {
		arg := args[i]
		if seen[arg] {
			return opts, false, "", fmt.Errorf("duplicate %s", arg)
		}
		seen[arg] = true
		switch arg {
		case "--report", "--json":
		case "--write-report":
			writeReport = true
		case "--days", "--provider", "--model", "--agent", "--auth", "--out":
			i++
			if i >= len(args) || args[i] == "" || strings.HasPrefix(args[i], "--") || strings.ContainsAny(args[i], "\x00\r\n") {
				return opts, false, "", fmt.Errorf("%s requires a value", arg)
			}
			value := args[i]
			switch arg {
			case "--days":
				days, err := strconv.Atoi(value)
				if err != nil || days < 0 || days > 3660 {
					return opts, false, "", fmt.Errorf("--days must be an integer from 0 to 3660")
				}

View on GitHub (pinned to 3ee70a1026)