{"record":{"id":"eb6efe86da6c9493","repo":"AlistGo/alist","slug":"user-is-not-allowed-to-access-via-ftp","errorCode":null,"errorMessage":"user is not allowed to access via FTP","messagePattern":"user is not allowed to access via FTP","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/ftp.go","lineNumber":136,"sourceCode":"\tvar err error\n\tif user == \"anonymous\" || user == \"guest\" {\n\t\tuserObj, err = op.GetGuest()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tuserObj, err = op.GetUserByName(user)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpassHash := model.StaticHash(pass)\n\t\tif err = userObj.ValidatePwdStaticHash(passHash); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tperm := common.MergeRolePermissions(userObj, userObj.BasePath)\n\tif userObj.Disabled || !common.HasPermission(perm, common.PermFTPAccess) {\n\t\treturn nil, errors.New(\"user is not allowed to access via FTP\")\n\t}\n\n\tctx := context.Background()\n\tctx = context.WithValue(ctx, \"user\", userObj)\n\tif user == \"anonymous\" || user == \"guest\" {\n\t\tctx = context.WithValue(ctx, \"meta_pass\", pass)\n\t} else {\n\t\tctx = context.WithValue(ctx, \"meta_pass\", \"\")\n\t}\n\tctx = context.WithValue(ctx, \"client_ip\", cc.RemoteAddr().String())\n\tctx = context.WithValue(ctx, \"proxy_header\", d.proxyHeader)\n\treturn ftp.NewAferoAdapter(ctx), nil\n}\n\nfunc (d *FtpMainDriver) GetTLSConfig() (*tls.Config, error) {\n\tif d.tlsConfig == nil {\n\t\treturn nil, errors.New(\"TLS config not provided\")\n\t}","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/server/ftp.go#L118-L154","documentation":"Returned by FtpMainDriver.AuthUser when the authenticated user is either disabled or whose merged role permissions do not include the PermFTPAccess bit. Permission is computed with common.MergeRolePermissions over the user's roles, so the effective FTP permission is the union of role permissions scoped to BasePath.","triggerScenarios":"FTP login (USER/PASS) with valid credentials where user.Disabled == true, or where none of the user's roles grant ftp access; also the guest/anonymous path when the guest user lacks the permission.","commonSituations":"FTP enabled in settings but the default role never got the 'ftp access' permission; a user was disabled for policy reasons but their FTP client still has saved credentials; after upgrading, roles were recreated without re-ticking the FTP permission.","solutions":["In the admin UI, edit the user's role(s) and enable the 'ftp access' permission (PermFTPAccess)","Un-disable the user (user settings page) if Disabled is the cause","Verify with an admin account that FTP works at all, confirming the server itself is healthy","For anonymous/guest FTP, grant the permission to the guest user specifically"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before exposing FTP to a user, mirror the server's check\nperm := common.MergeRolePermissions(userObj, userObj.BasePath)\nif userObj.Disabled || !common.HasPermission(perm, common.PermFTPAccess) {\n    return fmt.Errorf(\"deny FTP for %s: disabled or missing ftp access\", userObj.Username)\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"user is not allowed to access via FTP\") {\n    // surface a permission-fix hint to the admin instead of a generic auth failure\n    return fmt.Errorf(\"FTP denied: enable 'ftp access' on the user's role or un-disable the account\")\n}","preventionTips":["Audit roles for the ftp access bit whenever FTP/SFTP is enabled","Include an FTP smoke test (connect + login) in post-installation checklists","Remember guest/anonymous FTP needs the permission on the guest user too"],"tags":["ftp","auth","permissions","rbac"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}