kgretzky/evilginx2 · error

time duration value needs to start with a number

Error message

time duration value needs to start with a number

What it means

ParseDurationString requires each unit token to be preceded by a numeric value. If it hits a unit character (or any non-digit) while s_num is empty — meaning no digits accumulated since the last unit — it reports that the duration value must start with a number.

Source

Thrown at core/utils.go:124

						case 'd':
							days = val
						case 'h':
							hours = val
						case 'm':
							minutes = val
						case 's':
							seconds = val
						}
					} else {
						err = fmt.Errorf("you can only use time duration types in following order: 'd' > 'h' > 'm' > 's'")
						return
					}
				} else {
					err = fmt.Errorf("unknown time duration type: '%s', you can use only 'd', 'h', 'm' or 's'", string(c))
					return
				}
			} else {
				err = fmt.Errorf("time duration value needs to start with a number")
				return
			}
			s_num = ""
		}
	}
	t_dur = time.Duration(days)*24*time.Hour + time.Duration(hours)*time.Hour + time.Duration(minutes)*time.Minute + time.Duration(seconds)*time.Second
	return
}

func GetDurationString(t_now time.Time, t_expire time.Time) (ret string) {
	var days, hours, minutes, seconds int64
	ret = ""

	if t_expire.After(t_now) {
		t_dur := t_expire.Sub(t_now)
		if t_dur > 0 {
			days = int64(t_dur / (24 * time.Hour))
			t_dur -= time.Duration(days) * (24 * time.Hour)

View on GitHub (pinned to 4c0988a1d9)

Solutions

  1. Ensure every unit is directly preceded by digits: '1h30m', not '1h m'.
  2. Remove duplicate or dangling unit characters.
  3. Do not use signs or prefixes; the parser only accepts plain non-negative integers followed by a unit.

Example fix

// before
ParseDurationString("1h m")
// after
ParseDurationString("1h5m")
Defensive patterns

Strategy: validation

Validate before calling

var durRe = regexp.MustCompile(`^(?:\d+[dhms])+$`)
if !durRe.MatchString(durStr) {
    return fmt.Errorf("duration %q must be number+unit pairs, e.g. 1h30m", durStr)
}
d, err := core.ParseDurationString(durStr)

Type guard

func isNumberUnitPairs(s string) bool {
    prevDigit := false
    for i, c := range s {
        isDigit := c >= '0' && c <= '9'
        if i == 0 && !isDigit { return false }
        if !isDigit && !prevDigit { return false }
        if !isDigit && !strings.ContainsRune("dhms", c) { return false }
        prevDigit = isDigit
    }
    return prevDigit
}

Try / catch

d, err := core.ParseDurationString(input)
if err != nil {
    if strings.Contains(err.Error(), "start with a number") {
        log.Printf("%q has a unit without a preceding number", input)
        return
    }
    return err
}

Prevention

When it happens

Trigger: Strings that begin with a unit or contain consecutive units without a number between them, e.g. 'h30m', '1h m', '5m s', or a leading '-'.

Common situations: Typos like '1hh', duplicated separators, or pasting '±30m' / '-5m' strings where the sign or symbol precedes the digits.

Understand the failure class

Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.

Related errors


AI-assisted analysis of kgretzky/evilginx2@4c0988a1d9 (2026-09-05). Data as JSON: /api/errors/73f369fd03120324. Report an issue: GitHub.