{"record":{"id":"3100eaf9119c71ae","repo":"paperclipai/paperclip","slug":"connector-bad-response","errorCode":"CONNECTOR_BAD_RESPONSE","errorMessage":"Paperclip Cloud connector returned an invalid instance status","messagePattern":"Paperclip Cloud connector returned an invalid instance status","errorType":"error_code","errorClass":"PaperclipCloudConnectorError","httpStatus":null,"severity":"error","filePath":"server/src/services/paperclip-cloud-connector.ts","lineNumber":329,"sourceCode":"    return credentials;\n  }\n\n  return {\n    async getInstanceStatus(): Promise<\"active\" | \"suspended\" | \"removed\"> {\n      let response: ConnectorResponse;\n      try {\n        response = await call(\"status\", {\n          subject: \"instance-status\",\n          companyId: \"instance-status\",\n        });\n      } catch (error) {\n        if (error instanceof PaperclipCloudConnectorError && error.status === 401) return \"removed\";\n        throw error;\n      }\n      if (response.status === \"active\" && response.active === true) return \"active\";\n      if (response.status === \"suspended\" && response.active === false) return \"suspended\";\n      if (response.status === \"removed\" && response.active === false) return \"removed\";\n      throw new PaperclipCloudConnectorError(\"Paperclip Cloud connector returned an invalid instance status\", \"CONNECTOR_BAD_RESPONSE\");\n    },\n    async getCapabilities(): Promise<PaperclipCloudConnectorProfileId[]> {\n      let response: ConnectorResponse;\n      try {\n        response = await call(\"status\", {\n          subject: \"instance-capabilities\",\n          companyId: \"instance-capabilities\",\n        });\n      } catch {\n        return [];\n      }\n      if (response.active !== true || response.status !== \"active\" || !Array.isArray(response.profiles)) return [];\n      return [...new Set(response.profiles.flatMap((value) =>\n        typeof value === \"string\" && isPaperclipCloudConnectorProfileId(value) ? [value] : []\n      ))];\n    },\n    async startAuthorization(values: { subject: string; companyId: string; profile?: PaperclipCloudConnectorProfileId; returnUri: string; returnState: string }) {\n      const profile = values.profile ?? \"gmail.draft\";","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/paperclip-cloud-connector.ts#L311-L347","documentation":"getInstanceStatus polls the Paperclip Cloud broker's status endpoint and validates the response against a strict mapping: status 'active' requires active===true, 'suspended'/'removed' require active===false. If the broker returns a status/active combination that fits none of the accepted pairs, this error is thrown with CONNECTOR_BAD_RESPONSE.","triggerScenarios":"The broker's status response contains a status value outside {'active','suspended','removed'}, or an active boolean inconsistent with the status (e.g. status:'active' with active:false, or a missing/mistyped active field).","commonSituations":"Broker API version drift (new status value like 'degraded' the client doesn't know); a proxy returning an error page parsed loosely; a bug in the broker returning active:null.","solutions":["Check the broker's actual response payload for the instance and confirm status/active values","Upgrade the server package so the client recognizes the broker's new status values","If the broker introduced a new status, add a mapping branch before the throw and coordinate the contract change","Verify no intermediate proxy/CDN is mangling the JSON response"],"exampleFix":"// before\nconst status = await connector.getInstanceStatus(); // throws on unknown broker status\n\n// after\ntry {\n  const status = await connector.getInstanceStatus();\n} catch (e) {\n  if (e instanceof PaperclipCloudConnectorError && e.code === \"CONNECTOR_BAD_RESPONSE\") {\n    logger.error(\"broker status payload unrecognized\", e);\n    // fall back to treating instance as suspended / surface to operator\n  } else { throw e; }\n}","handlingStrategy":"try-catch","validationCode":"// pre-validate the broker payload shape if you call the status endpoint yourself\nfunction isValidInstanceStatus(r: unknown): r is { status: string; active: boolean } {\n  return typeof r === \"object\" && r !== null\n    && [\"active\", \"suspended\", \"removed\"].includes((r as any).status)\n    && typeof (r as any).active === \"boolean\";","typeGuard":"function isKnownInstanceStatus(s: unknown): s is \"active\" | \"suspended\" | \"removed\" {\n  return s === \"active\" || s === \"suspended\" || s === \"removed\";","tryCatchPattern":"try {\n  const status = await connector.getInstanceStatus();\n} catch (e) {\n  if (isPaperclipCloudConnectorError(e) && e.code === \"CONNECTOR_BAD_RESPONSE\") {\n    // treat instance state as unknown; alert operator instead of acting on it\n  } else throw e;\n}","preventionTips":["Pin broker and client to compatible versions","Monitor broker responses for new status values after upgrades","Add contract tests covering every status/active pair the broker can emit"],"tags":["connector","broker","response-validation"],"backgroundTag":"unexpected-api-response-shape","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"}