robfig/cron · error

too many hyphens

Error message

too many hyphens: %s

What it means

getRange splits an expression on '-' to extract a range's low and high bounds. An expression with more than one hyphen has no valid two-endpoint interpretation, so it is rejected with this error naming the offending expression.

Solutions

  1. Use at most one hyphen per field component (low-high)
  2. Express multiple values with commas instead: 1,2,3 not 1-2-3
  3. Validate each field with a regex like ^\d+-\d+$ before parsing

Example fix

// before
sched, err := p.Parse("0 0 1-2-3 * *")
// after
sched, err := p.Parse("0 0 1-3 * *")  // range
// or
sched, err := p.Parse("0 0 1,2,3 * *") // list
Defensive patterns

Strategy: validation

Validate before calling

var hyphenRe = regexp.MustCompile(`^[^-]+-[^-]+$`)
func fieldHasSingleHyphen(f string) bool {
	return !strings.Contains(f[:strings.Index(f, "-")+1]+strings.TrimPrefix(f, f[:strings.Index(f, "-")+1]), "-") || hyphenRe.MatchString(f)
}

Try / catch

sched, err := parser.Parse(spec)
if err != nil {
	return fmt.Errorf("malformed range in cron spec %q: %w", spec, err)
}

Prevention

When it happens

Trigger: Specs like "1-2-3" in any field, or negative-looking tokens such as "*-*-5" produced by templating mistakes; also a range glued to another hyphenated token.

Common situations: Typo while editing cron fields; template substitution injecting extra hyphens; misunderstanding syntax and trying to express a list with hyphens (should use commas).

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of robfig/cron@bc59245fe1 (2026-09-07). Data as JSON: /api/errors/7d887615ac8651d8. Report an issue: GitHub.

Appendix: source

Thrown at parser.go:280

	if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" {
		start = r.min
		end = r.max
		extra = starBit
	} else {
		start, err = parseIntOrName(lowAndHigh[0], r.names)
		if err != nil {
			return 0, err
		}
		switch len(lowAndHigh) {
		case 1:
			end = start
		case 2:
			end, err = parseIntOrName(lowAndHigh[1], r.names)
			if err != nil {
				return 0, err
			}
		default:
			return 0, fmt.Errorf("too many hyphens: %s", expr)
		}
	}

	switch len(rangeAndStep) {
	case 1:
		step = 1
	case 2:
		step, err = mustParseInt(rangeAndStep[1])
		if err != nil {
			return 0, err
		}

		// Special handling: "N/step" means "N-max/step".
		if singleDigit {
			end = r.max
		}
		if step > 1 {
			extra = 0

View on GitHub (pinned to bc59245fe1)