robfig/cron · error

parser does not accept descriptors

Error message

parser does not accept descriptors: %v

What it means

Parse treats specs starting with '@' as named descriptors (@yearly, @hourly, etc.), but only if the Descriptor option was passed to NewParser. Without that bit, any '@'-prefixed spec is rejected with this error naming the offending spec.

Solutions

  1. Add cron.Descriptor to the NewParser option mask
  2. Strip/handle @descriptors in caller code before Parse when descriptors should be unsupported
  3. Use cron.ParseStandard instead of a custom NewParser if standard behavior is desired

Example fix

// before
p := cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow)
s, err := p.Parse("@daily") // error
// after
p := cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)
s, err := p.Parse("@daily")
Defensive patterns

Strategy: validation

Validate before calling

if strings.HasPrefix(spec, "@") && parserOptions&cron.Descriptor == 0 {
	return fmt.Errorf("descriptors like %q require the Descriptor parser option", spec)
}

Try / catch

sched, err := parser.Parse(spec)
if err != nil && strings.HasPrefix(spec, "@") {
	return fmt.Errorf("descriptor unsupported by this parser: %w", err)
}

Prevention

When it happens

Trigger: Calling Parse("@daily") or Parse("@every 1h") on a Parser created without the Descriptor option bit, e.g. NewParser(Minute|Hour|Dom|Month|Dow).

Common situations: Using cron.ParseStandard works but a custom NewParser call forgot Descriptor; upgrading or replacing cron.Parse with a hand-rolled NewParser and losing descriptor support; user-submitted specs containing @strings.

Related errors


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

Appendix: source

Thrown at parser.go:108

		return nil, fmt.Errorf("empty spec string")
	}

	// Extract timezone if present
	var loc = time.Local
	if strings.HasPrefix(spec, "TZ=") || strings.HasPrefix(spec, "CRON_TZ=") {
		var err error
		i := strings.Index(spec, " ")
		eq := strings.Index(spec, "=")
		if loc, err = time.LoadLocation(spec[eq+1 : i]); err != nil {
			return nil, fmt.Errorf("provided bad location %s: %v", spec[eq+1:i], err)
		}
		spec = strings.TrimSpace(spec[i:])
	}

	// Handle named schedules (descriptors), if configured
	if strings.HasPrefix(spec, "@") {
		if p.options&Descriptor == 0 {
			return nil, fmt.Errorf("parser does not accept descriptors: %v", spec)
		}
		return parseDescriptor(spec, loc)
	}

	// Split on whitespace.
	fields := strings.Fields(spec)

	// Validate & fill in any omitted or optional fields
	var err error
	fields, err = normalizeFields(fields, p.options)
	if err != nil {
		return nil, err
	}

	field := func(field string, r bounds) uint64 {
		if err != nil {
			return 0
		}

View on GitHub (pinned to bc59245fe1)