{"record":{"id":"da87ba568a75bc82","repo":"larksuite/cli","slug":"app-registration-returned-credentials-with-a-contr","errorCode":null,"errorMessage":"app registration returned credentials with a contradictory tenant brand %q","messagePattern":"app registration returned credentials with a contradictory tenant brand %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/app_registration.go","lineNumber":289,"sourceCode":"\t\terrStr := getStr(data, \"error\")\n\t\tif errStr == \"\" {\n\t\t\tresult := &AppRegistrationResult{\n\t\t\t\tClientID:     getStr(data, \"client_id\"),\n\t\t\t\tClientSecret: getStr(data, \"client_secret\"),\n\t\t\t}\n\t\t\tif userInfoRaw, ok := data[\"user_info\"].(map[string]interface{}); ok {\n\t\t\t\tresult.UserInfo = &AppRegUserInfo{\n\t\t\t\t\tOpenID:      getStr(userInfoRaw, \"open_id\"),\n\t\t\t\t\tTenantBrand: getStr(userInfoRaw, \"tenant_brand\"),\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif result.ClientID != \"\" && result.ClientSecret != \"\" {\n\t\t\t\t// The issuing domain is authoritative; a contradictory final\n\t\t\t\t// tenant report is a protocol violation, not a brand override.\n\t\t\t\tif result.UserInfo != nil && result.UserInfo.TenantBrand != \"\" &&\n\t\t\t\t\tcore.ParseBrand(result.UserInfo.TenantBrand) != effectiveBrand {\n\t\t\t\t\treturn nil, effectiveBrand, fmt.Errorf(\"app registration returned credentials with a contradictory tenant brand %q\", result.UserInfo.TenantBrand)\n\t\t\t\t}\n\t\t\t\treturn result, effectiveBrand, nil\n\t\t\t}\n\t\t\t// Incomplete credentials without an error: keep polling.\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch errStr {\n\t\tcase \"authorization_pending\":\n\t\t\tcontinue\n\t\tcase \"slow_down\":\n\t\t\tinterval = minInt(interval+5, maxPollIntervalSeconds)\n\t\t\tfmt.Fprintf(errOut, \"[lark-cli] app-registration: slow_down, interval increased to %ds\\n\", interval)\n\t\t\tcontinue\n\t\tcase \"access_denied\":\n\t\t\treturn nil, effectiveBrand, ErrRegistrationDenied\n\t\tcase \"expired_token\", \"invalid_grant\":\n\t\t\treturn nil, effectiveBrand, ErrRegistrationExpired","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/auth/app_registration.go#L271-L307","documentation":"Thrown by RegisterAppWithDiscovery at internal/auth/app_registration.go:289 when a poll returns complete credentials (client_id + client_secret) whose user_info.tenant_brand parses to a brand different from the domain that actually issued them (effectiveBrand). The library treats the issuing domain as authoritative, so a contradicting final tenant report is a server protocol violation and registration aborts instead of silently overriding the brand.","triggerScenarios":"Server returns credentials on domain A (e.g. feishu) while the final user_info.tenant_brand says brand B (e.g. lark), after the one permitted cross-brand switch already happened (switched=true prevents further switches but a later contradictory report still triggers this).","commonSituations":"User belongs to a tenant on the opposite brand from the polled domain at the exact moment credentials are issued; server-side brand-propagation race; tenant migrated brands mid-registration; backend bug emitting a stale tenant_brand in the final successful poll.","solutions":["Restart the registration flow — a transient race may resolve on the next run.","Ensure the account you approve in the browser belongs to the brand matching your region (Feishu vs Lark); approve with the correct account/tenant.","Update the CLI and retry in case the server bug was fixed; check for known issues.","If reproducible with a specific tenant, report the tenant_brand/issuing-domain pair to the service maintainers — this indicates a server protocol violation."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func tenantBrandMatches(brand core.LarkBrand, ui *AppRegUserInfo) bool {\n    return ui == nil || ui.TenantBrand == \"\" || core.ParseBrand(ui.TenantBrand) == brand\n}","tryCatchPattern":"result, brand, err := RegisterAppWithDiscovery(ctx, client, resp, errOut)\nif err != nil {\n    if strings.Contains(err.Error(), \"contradictory tenant brand\") {\n        // protocol violation: restart the flow and approve with the brand-correct account\n    }\n    return err\n}","preventionTips":["Approve registration in the browser with an account whose tenant matches your regional brand.","Avoid tenant brand migrations during an active registration.","Keep the CLI and server protocol versions aligned; report reproducible mismatches."],"tags":["protocol","device-flow","brand-mismatch","tenant"],"backgroundTag":"tenant-brand-mismatch","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}