{"record":{"id":"fc60a6241ef357d7","repo":"multica-ai/multica","slug":"composio-callback-missing-connected-account-id","errorCode":null,"errorMessage":"composio: callback missing connected_account_id","messagePattern":"composio: callback missing connected_account_id","errorType":"http","errorClass":null,"httpStatus":302,"severity":"error","filePath":"server/internal/integrations/composio/service.go","lineNumber":299,"sourceCode":"// CompleteCallback verifies the signed state and, on a successful Composio\n// status, upserts the local connection row. It returns the toolkit slug from\n// the state so the handler can build the right redirect even on the\n// not-successful path.\n//\n// Idempotency: the upsert is keyed on (user_id, connected_account_id), so a\n// duplicate callback re-activates the same row instead of creating a second.\nfunc (s *Service) CompleteCallback(ctx context.Context, state, status, connectedAccountID string) (string, error) {\n\tclaims, err := verifyState(s.secret, state, s.now())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif !strings.EqualFold(strings.TrimSpace(status), \"success\") {\n\t\t// Honor the state for the redirect slug, but do not write an active row.\n\t\treturn claims.ToolkitSlug, ErrConnectNotSuccessful\n\t}\n\tif strings.TrimSpace(connectedAccountID) == \"\" {\n\t\treturn claims.ToolkitSlug, errors.New(\"composio: callback missing connected_account_id\")\n\t}\n\n\tuserID, err := util.ParseUUID(claims.UserID)\n\tif err != nil {\n\t\treturn claims.ToolkitSlug, fmt.Errorf(\"composio: state has invalid user id: %w\", err)\n\t}\n\n\t// The auth_config_id was resolved at BeginConnect and signed into the state,\n\t// so we compare against THAT exact value rather than re-resolving here (a\n\t// re-resolve that failed or drifted would otherwise fail-open: a missing\n\t// expected auth config used to skip the check, letting another toolkit's\n\t// account id be bound under this toolkit's slug). An empty value fails\n\t// closed in verifyAccountOwnership.\n\tauthConfigID := claims.AuthConfigID\n\n\t// Defense-in-depth (PR 4608 review): the signed state proves *who* started\n\t// the handshake and *which* toolkit, but connected_account_id rides back as\n\t// a plain query param Composio appends to our callback URL. A crafted","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/integrations/composio/service.go#L281-L317","documentation":"Error \"composio: callback missing connected_account_id\" thrown in multica-ai/multica.","triggerScenarios":"Thrown at server/internal/integrations/composio/service.go:299 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Restart the Composio OAuth flow; the callback was missing the connected_account_id parameter."],"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-15T22:17:37.221Z"}