{"record":{"id":"7089cedf1f75f427","repo":"juicedata/juicefs","slug":"invalid-quota-type-d","errorCode":null,"errorMessage":"invalid quota type: %d","messagePattern":"invalid quota type: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/meta/redis.go","lineNumber":4618,"sourceCode":"\t\tfor _, q := range quotas {\n\t\t\tconfig, err := m.getQuotaKeys(q.qtype)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tkey := strconv.FormatUint(q.qkey, 10)\n\t\t\tpipe.HSetNX(ctx, config.quotaKey, key, m.packQuota(-1, -1))\n\t\t\tpipe.HIncrBy(ctx, config.usedSpaceKey, key, q.quota.newSpace)\n\t\t\tpipe.HIncrBy(ctx, config.usedInodesKey, key, q.quota.newInodes)\n\t\t}\n\t\treturn nil\n\t})\n\treturn err\n}\n\nfunc (m *redisMeta) cleanUgUsage(ctx Context, qtype uint32) error {\n\tif qtype != UserQuotaType && qtype != GroupQuotaType {\n\t\treturn fmt.Errorf(\"invalid quota type: %d\", qtype)\n\t}\n\tconfig, err := m.getQuotaKeys(qtype)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn m.hscan(ctx, config.quotaKey, func(keys []string) error {\n\t\t_, err := m.rdb.TxPipelined(ctx, func(pipe redis.Pipeliner) error {\n\t\t\tfor i := 0; i < len(keys); i += 2 {\n\t\t\t\tkey := keys[i]\n\t\t\t\tpipe.HSet(ctx, config.usedSpaceKey, key, 0)\n\t\t\t\tpipe.HSet(ctx, config.usedInodesKey, key, 0)\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t\treturn err\n\t})\n}\n","sourceCodeStart":4600,"sourceCodeEnd":4636,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/meta/redis.go#L4600-L4636","documentation":"Returned by cleanUgUsage (redis.go:4618) when the qtype argument is neither UserQuotaType nor GroupQuotaType. cleanUgUsage clears per-user/per-group used-usage hashes, so only those two quota types are valid; passing any other value (0, DirQuotaType, arbitrary integers) is rejected before any Redis keys are touched.","triggerScenarios":"Calling cleanUgUsage (or the internal paths that dispatch to it) with a qtype value other than UserQuotaType/GroupQuotaType — e.g. passing DirQuotaType to a user/group cleanup routine, or an uninitialized/zero uint32.","commonSituations":"Custom tooling calling internal meta APIs with the wrong quota-type constant; a code path confusing directory quotas (which have their own cleanup) with user/group quotas; uninitialized variable in a patch.","solutions":["Pass the correct constant: meta.UserQuotaType or meta.GroupQuotaType, depending on which usage you intend to clean.","If you meant to clean directory quota usage, use the directory-quota cleanup path instead of cleanUgUsage.","Verify the caller's qtype variable is initialized (a zero-value uint32 will fail this check)."],"exampleFix":"// before\nerr = m.cleanUgUsage(ctx, DirQuotaType)\n// after\nerr = m.cleanUgUsage(ctx, UserQuotaType) // or GroupQuotaType","handlingStrategy":"validation","validationCode":"if qtype != meta.UserQuotaType && qtype != meta.GroupQuotaType {\n    return fmt.Errorf(\"cleanUgUsage requires UserQuotaType or GroupQuotaType, got %d\", qtype)\n}","typeGuard":"func isUgQuotaType(t uint32) bool { return t == meta.UserQuotaType || t == meta.GroupQuotaType }","tryCatchPattern":"if err := m.cleanUgUsage(ctx, qtype); err != nil {\n    if strings.Contains(err.Error(), \"invalid quota type\") {\n        // caller bug: check the constant passed\n    }\n    return err\n}","preventionTips":["Reference named constants (meta.UserQuotaType/meta.GroupQuotaType) instead of raw integers.","Remember directory quotas have a separate cleanup path — don't route them through cleanUgUsage.","Initialize qtype variables; a zero-value uint32 fails this check."],"tags":["redis","quota","invalid-argument"],"backgroundTag":"invalid-enum-value","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}