{"record":{"id":"4a1c60f724921c2c","repo":"multica-ai/multica","slug":"dingtalk-redeemer-is-not-a-workspace-member","errorCode":null,"errorMessage":"dingtalk: redeemer is not a workspace member","messagePattern":"dingtalk: redeemer is not a workspace member","errorType":"http","errorClass":"ErrBindingNotWorkspaceMember","httpStatus":403,"severity":"error","filePath":"server/internal/integrations/dingtalk/binding.go","lineNumber":40,"sourceCode":"// by the OutboundReplier), clicks through to the in-product redeem page, and\n// their DingTalk staff id is bound to their Multica account. It mirrors\n// slack.BindingTokenService but runs on the generic channel_* queries with\n// channel_type='dingtalk'.\n\n// BindingTokenTTL bounds a token's life. The channel_binding_token CHECK\n// enforces the same 15-minute cap so a misconfigured caller cannot mint longer.\nconst BindingTokenTTL = 15 * time.Minute\n\nvar (\n\t// ErrBindingTokenInvalid: token unknown / already consumed / expired. One\n\t// opaque error for all three avoids a replay timing oracle.\n\tErrBindingTokenInvalid = errors.New(\"dingtalk: binding token invalid or expired\")\n\t// ErrBindingAlreadyAssigned: this DingTalk user id is already bound to a\n\t// different Multica user (account transfer must go through explicit unbind).\n\tErrBindingAlreadyAssigned = errors.New(\"dingtalk: user id is already bound to a different user\")\n\t// ErrBindingNotWorkspaceMember: the redeemer is not a member of the token's\n\t// workspace. Translated to 403 at the HTTP boundary.\n\tErrBindingNotWorkspaceMember = errors.New(\"dingtalk: redeemer is not a workspace member\")\n)\n\n// BindingToken is a freshly minted token. The raw value is returned exactly\n// once (embedded in the binding URL); only its hash is persisted.\ntype BindingToken struct {\n\tRaw       string\n\tExpiresAt time.Time\n}\n\n// RedeemedBindingToken is returned after a successful redemption.\ntype RedeemedBindingToken struct {\n\tWorkspaceID    pgtype.UUID\n\tInstallationID pgtype.UUID\n\tDingTalkUserID string\n}\n\n// BindingTokenService mints and redeems DingTalk binding tokens. Redemption is\n// transactional: consuming the token and inserting the channel_user_binding row","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/integrations/dingtalk/binding.go#L22-L58","documentation":"Error \"dingtalk: redeemer is not a workspace member\" thrown in multica-ai/multica.","triggerScenarios":"Thrown at server/internal/integrations/dingtalk/binding.go:40 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Join the workspace before redeeming the DingTalk binding token."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}