{"record":{"id":"08afcbf1ca828d8f","repo":"paperclipai/paperclip","slug":"connector-config-invalid","errorCode":"CONNECTOR_CONFIG_INVALID","errorMessage":"GitHub access token is required to authorize a webhook binding","messagePattern":"GitHub access token is required to authorize a webhook binding","errorType":"error_code","errorClass":"PaperclipCloudConnectorError","httpStatus":null,"severity":"error","filePath":"server/src/services/paperclip-cloud-connector.ts","lineNumber":423,"sourceCode":"        values.companyId,\n        profile,\n      );\n    },\n    async revoke(values: { subject: string; companyId: string; profile?: PaperclipCloudConnectorProfileId; token: string }) {\n      await call(\"revoke\", { ...values, profile: values.profile ?? \"gmail.draft\" }, { field: \"token\", value: values.token });\n    },\n    async setWebhookBinding(values: {\n      subject: string;\n      companyId: string;\n      id: string;\n      installationId: string;\n      connectionId: string;\n      grantId: string;\n      active: boolean;\n      accessToken?: string;\n    }) {\n      if (values.active && !values.accessToken) {\n        throw new PaperclipCloudConnectorError(\n          \"GitHub access token is required to authorize a webhook binding\",\n          \"CONNECTOR_CONFIG_INVALID\",\n        );\n      }\n      const binding = JSON.stringify({\n        id: values.id,\n        installationId: values.installationId,\n        connectionId: values.connectionId,\n        grantId: values.grantId,\n        active: values.active,\n        ...(values.active ? { accessToken: values.accessToken } : {}),\n      });\n      await call(\"webhook-bind\", { ...values, profile: \"github.code\" }, { field: \"binding\", value: binding });\n    },\n    async leaseEvents(values: { subject: string; companyId: string }): Promise<{ leaseId: string; events: SealedConnectorEvents[\"events\"] } | null> {\n      const response = await call(\"event-lease\", values);\n      if (Array.isArray(response.events) && response.events.length === 0) return null;\n      if (typeof response.leaseId !== \"string\") {","sourceCodeStart":405,"sourceCodeEnd":441,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/paperclip-cloud-connector.ts#L405-L441","documentation":"setWebhookBinding refuses to activate a GitHub webhook binding (values.active === true) when no GitHub access token is supplied. Activating a binding authorizes Paperclip Cloud to register/deliver webhooks, which requires the token; without it the binding would be non-functional, so CONNECTOR_CONFIG_INVALID is thrown.","triggerScenarios":"Calling setWebhookBinding with { active: true } and accessToken undefined — e.g. toggling an existing binding active from a stored record that lacks the token, or constructing the values object without the credential available.","commonSituations":"Caller re-activates a binding persisted without its token (tokens not stored at rest); credential rotation removed the GitHub token before the binding update; code path passes active from config but forgets to pass the token field.","solutions":["Fetch/load the GitHub access token (e.g. via connector claim/openCredentials) and pass it in values.accessToken before activating","If the token was never stored, run the GitHub authorization flow again to obtain one, then call setWebhookBinding","If only deactivating, pass active: false — the token is not required for deactivation","Add a pre-check in the calling code so activation never proceeds without a token"],"exampleFix":"// before\nawait connector.setWebhookBinding({ id, connectionId, grantId, active: true }); // throws\n\n// after\nconst { accessToken } = await connector.claim({ subject, companyId });\nawait connector.setWebhookBinding({ id, connectionId, grantId, active: true, accessToken });","handlingStrategy":"validation","validationCode":"// guard before calling\nfunction assertBindingActivatable(values: { active: boolean; accessToken?: string }): void {\n  if (values.active && !values.accessToken) {\n    throw new Error(\"accessToken required to activate webhook binding\");\n  }\n}","typeGuard":"function canActivateBinding(v: { active: boolean; accessToken?: string }): v is { active: true; accessToken: string } {\n  return !v.active || typeof v.accessToken === \"string\" && v.accessToken.length > 0;","tryCatchPattern":"try {\n  await connector.setWebhookBinding(values);\n} catch (e) {\n  if (isPaperclipCloudConnectorError(e) && e.code === \"CONNECTOR_CONFIG_INVALID\") {\n    // acquire a GitHub token via claim/authorization, then retry\n  } else throw e;\n}","preventionTips":["Load the GitHub access token as part of the binding-update flow, never optional when active:true","Persist enough binding state (or re-claim credentials) so re-activation has a token available","Deactivate (active:false) does not need a token — separate activate/deactivate code paths"],"tags":["config","github","webhook","missing-token"],"backgroundTag":"missing-credentials","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}