semaphoreui/semaphore · error
invalid --ttl value
Error message
invalid --ttl value: %w
What it means
createUserToken parses the --ttl flag with time.ParseDuration; if the value is not a valid Go duration string it returns 'invalid --ttl value: <cause>'. The TTL determines the token's expiry (now + duration); an unparseable value aborts token creation.
Solutions
- Use a valid Go duration: composite units like '24h', '720h' (30 days), '8760h' (a year), or '30m'
- Convert days to hours since Go has no 'd' unit (e.g. 7 days = 168h)
- Omit --ttl entirely for a non-expiring token
Example fix
// before semaphore user token create --login john --ttl 30d // after semaphore user token create --login john --ttl 720h
Defensive patterns
Strategy: validation
Validate before calling
if ! [[ "$TTL" =~ ^[0-9]+(ns|us|µs|ms|s|m|h)+$ ]]; then echo "--ttl must be a Go duration like 720h"; exit 1; fi semaphore user token create --login "$LOGIN" --ttl "$TTL"
Prevention
- Use only Go duration units: ns, us, ms, s, m, h — never d or w
- Convert days to hours (30d = 720h)
- Omit --ttl for non-expiring tokens
- Echo the computed expiry in scripts to sanity-check the duration
When it happens
Trigger: Running `semaphore user token create --login <u> --ttl <bad>` where <bad> is not a valid Go duration (e.g. '30d', '1w', '2 hours', or a bare number).
Common situations: Using day/week units that Go durations don't support ('30d'); including spaces ('2 hours'); forgetting the unit entirely ('30'); passing a relative date instead of a duration.
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
- argument --login required
- user with login not found
- Cannot specify both --undo-to and --apply-to
- no admins found in database; create a admin first
- Empty token
AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07).
Data as JSON: /api/errors/49957912f53c1650.
Report an issue: GitHub.
Appendix: source
Thrown at cli/cmd/user_token.go:73
}
if err != nil {
return db.User{}, err
}
return user, nil
}
func createUserToken(store db.Store, out io.Writer, args tokenArgs) error {
user, err := getTokenUser(store, args.login)
if err != nil {
return err
}
var expiresAt *time.Time
if args.ttl != "" {
d, err := time.ParseDuration(args.ttl)
if err != nil {
return fmt.Errorf("invalid --ttl value: %w", err)
}
t := tz.Now().Add(d)
expiresAt = &t
}
tokenID := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, tokenID); err != nil {
return err
}
token, err := store.CreateAPIToken(db.APIToken{
ID: strings.ToLower(base64.URLEncoding.EncodeToString(tokenID)),
UserID: user.ID,
Expired: false,
ExpiresAt: expiresAt,
Name: args.name,
})
if err != nil {View on GitHub (pinned to 1774ccb71a)