{"record":{"id":"220f552c52281b8f","repo":"tailscale/tailscale","slug":"w-actual-length-is-d","errorCode":null,"errorMessage":"%w, actual length is %d","messagePattern":"%w, actual length is (.+?)","errorType":"validation","errorClass":"ErrBadSrcName","httpStatus":null,"severity":"error","filePath":"util/winutil/s4u/lsa_windows.go","lineNumber":260,"sourceCode":"\tif err != nil {\n\t\treturn username, false, err\n\t}\n\n\tif strings.EqualFold(before, comp) {\n\t\treturn after, false, nil\n\t}\n\treturn username, true, nil\n}\n\n// logonAs performs a S4U logon for u on behalf of srcName, and returns an\n// access token for the user if successful. srcName must be non-empty, ASCII,\n// and no more than 8 characters long. If srcName does not meet this criteria,\n// LogonAs will return ErrBadSrcName wrapped with additional information; use\n// errors.Is to check for it. When capLevel == CapCreateProcess, the logon\n// enforces the user's logon hours policy (when present).\nfunc (ls *lsaSession) logonAs(srcName string, u *user.User, capLevel CapabilityLevel) (token windows.Token, err error) {\n\tif ln := len(srcName); ln == 0 || ln > _TOKEN_SOURCE_LENGTH {\n\t\treturn 0, fmt.Errorf(\"%w, actual length is %d\", ErrBadSrcName, ln)\n\t}\n\tif err := checkASCII(srcName); err != nil {\n\t\treturn 0, fmt.Errorf(\"%w: %v\", ErrBadSrcName, err)\n\t}\n\n\tsanitizedUserName, isDomainUser, err := checkDomainAccount(u.Username)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif isDomainUser && !winenv.IsDomainJoined() {\n\t\treturn 0, fmt.Errorf(\"%w: cannot logon as domain user without being joined to a domain\", os.ErrInvalid)\n\t}\n\n\tvar pkgID uint32\n\tvar authInfo unsafe.Pointer\n\tvar authInfoLen uint32\n\tenforceLogonHours := capLevel == CapCreateProcess\n\tif isDomainUser {","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/tailscale/tailscale/blob/6e0912f97994f927632b34ae9e63b53d6516a6ac/util/winutil/s4u/lsa_windows.go#L242-L278","documentation":"logonAs rejects a token source name whose length is 0 or greater than _TOKEN_SOURCE_LENGTH (8), the fixed size of TOKEN_SOURCE.SourceName. The error wraps the ErrBadSrcName sentinel and reports the actual length, so errors.Is(err, ErrBadSrcName) detects it.","triggerScenarios":"Calling s4u.Login / ListGroupIDsForSSHPreAuthOnly with an empty srcName, or with a long human-readable service name (9+ characters) instead of a short source tag.","commonSituations":"Passing service display names (\"My Company Agent\") where an 8-char tag is required; defaulting the argument to the empty string when config is missing.","solutions":["Use a constant source name that is 1-8 ASCII characters (e.g. \"tssvc\")","Validate length at config load time so the failure surfaces before any LSA work","Handle ErrBadSrcName with errors.Is to give a precise error message"],"exampleFix":"// before\nsrcName := \"my-long-service-name\" // 20 chars\n\n// after\nconst srcName = \"tssvc\" // <= 8 chars, ASCII\n// or: if len(srcName) == 0 || len(srcName) > 8 { return cfgError }","handlingStrategy":"validation","validationCode":"const maxSrcName = 8 // _TOKEN_SOURCE_LENGTH\nif len(srcName) == 0 || len(srcName) > maxSrcName {\n    return fmt.Errorf(\"srcName must be 1-%d ASCII characters\", maxSrcName)\n}","typeGuard":null,"tryCatchPattern":"sess, err := s4u.Login(logf, srcName, u, capLevel)\nif err != nil {\n    if errors.Is(err, s4u.ErrBadSrcName) {\n        return fmt.Errorf(\"bad srcName (len=%d); use 1-8 ASCII chars\", len(srcName))\n    }\n    return err\n}","preventionTips":["Reserve a short fixed tag (e.g. \"tssvc\") as the source name","Validate source names at config load, not at logon time","Remember TOKEN_SOURCE.SourceName is 8 bytes - the limit is structural"],"tags":["go","windows","lsa","s4u","length-validation","token-source"],"backgroundTag":"invalid-token-source-name","analyzedSha":"6e0912f97994f927632b34ae9e63b53d6516a6ac","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}