glanceapp/glance · error

invalid duration format: %s

Error message

invalid duration format: %s

What it means

Returned by durationField.UnmarshalYAML when a duration value in config does not match the strict pattern ^(\d+)(s|m|h|d)$ — a whole number followed by exactly one unit letter (seconds, minutes, hours, days). No combined units, no decimals, no ms/µs, no bare numbers are accepted.

Source

Thrown at internal/glance/config-fields.go:110

	return nil
}

var durationFieldPattern = regexp.MustCompile(`^(\d+)(s|m|h|d)$`)

type durationField time.Duration

func (d *durationField) UnmarshalYAML(node *yaml.Node) error {
	var value string

	if err := node.Decode(&value); err != nil {
		return err
	}

	matches := durationFieldPattern.FindStringSubmatch(value)

	if len(matches) != 3 {
		return fmt.Errorf("invalid duration format: %s", value)
	}

	duration, err := strconv.Atoi(matches[1])
	if err != nil {
		return err
	}

	switch matches[2] {
	case "s":
		*d = durationField(time.Duration(duration) * time.Second)
	case "m":
		*d = durationField(time.Duration(duration) * time.Minute)
	case "h":
		*d = durationField(time.Duration(duration) * time.Hour)
	case "d":
		*d = durationField(time.Duration(duration) * 24 * time.Hour)
	}

View on GitHub (pinned to 91324e8de7)

Solutions

  1. Use a single integer plus one unit: e.g. cache: 90s, cache: 30m, cache: 12h, cache: 7d.
  2. Convert combined durations to the largest unit (90m → 1h loses precision, so use 5400s or 90m as appropriate).
  3. Convert decimals to a smaller unit (0.5h → 30m).
  4. Validate with `glance config:validate` after editing.

Example fix

# before
cache: 1h30m

# after
cache: 90m
Defensive patterns

Strategy: validation

Validate before calling

python3 - <<'EOF'
import re,sys,yaml
pat=re.compile(r'^(\d+)(s|m|h|d)$')
def walk(o):
    if isinstance(o,dict):
        for k,v in o.items():
            if k in ('cache','cache-duration','secret-effect-duration') and isinstance(v,str) and not pat.match(v):
                sys.exit(f'bad duration: {k}={v}')
            walk(v)
    elif isinstance(o,list):
        for i in o: walk(i)
walk(yaml.safe_load(open('glance.yml')))
print('ok')
EOF

Prevention

When it happens

Trigger: Writing cache: 90 (no unit), cache: 1h30m, cache: 1.5h, cache: 500ms, cache: 1 w, or cache: 1H (uppercase). Any of these fails FindStringSubmatch with fewer than 3 groups.

Common situations: Assuming Go duration string syntax (1h30m) is accepted; writing milliseconds; uppercase units; fractional values like 0.5d; bare seconds without 's'.

Related errors


AI-assisted analysis of glanceapp/glance@91324e8de7 (2026-08-15). Data as JSON: /api/errors/be1a2bf43d0f24ee. Report an issue: GitHub.