{"record":{"id":"49957912f53c1650","repo":"semaphoreui/semaphore","slug":"invalid-ttl-value-w","errorCode":null,"errorMessage":"invalid --ttl value: %w","messagePattern":"invalid --ttl value: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/cmd/user_token.go","lineNumber":73,"sourceCode":"\t}\n\tif err != nil {\n\t\treturn db.User{}, err\n\t}\n\n\treturn user, nil\n}\n\nfunc createUserToken(store db.Store, out io.Writer, args tokenArgs) error {\n\tuser, err := getTokenUser(store, args.login)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar expiresAt *time.Time\n\tif args.ttl != \"\" {\n\t\td, err := time.ParseDuration(args.ttl)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid --ttl value: %w\", err)\n\t\t}\n\t\tt := tz.Now().Add(d)\n\t\texpiresAt = &t\n\t}\n\n\ttokenID := make([]byte, 32)\n\tif _, err := io.ReadFull(rand.Reader, tokenID); err != nil {\n\t\treturn err\n\t}\n\n\ttoken, err := store.CreateAPIToken(db.APIToken{\n\t\tID:        strings.ToLower(base64.URLEncoding.EncodeToString(tokenID)),\n\t\tUserID:    user.ID,\n\t\tExpired:   false,\n\t\tExpiresAt: expiresAt,\n\t\tName:      args.name,\n\t})\n\tif err != nil {","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/cli/cmd/user_token.go#L55-L91","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nsemaphore user token create --login john --ttl 30d\n// after\nsemaphore user token create --login john --ttl 720h","handlingStrategy":"validation","validationCode":"if ! [[ \"$TTL\" =~ ^[0-9]+(ns|us|µs|ms|s|m|h)+$ ]]; then echo \"--ttl must be a Go duration like 720h\"; exit 1; fi\nsemaphore user token create --login \"$LOGIN\" --ttl \"$TTL\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["cli","ttl","duration-parsing","user-tokens"],"backgroundTag":"invalid-duration-format","analyzedSha":"1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa","analyzedAt":"2026-09-07T11:00:33.293Z","contentChangedAt":"2026-09-07T11:00:33.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}