{"record":{"id":"f8094d5a3fe80a1f","repo":"hoppscotch/hoppscotch","slug":"failed-to-delete-mock-server","errorCode":null,"errorMessage":"Failed to delete mock server","messagePattern":"Failed to delete mock server","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/hoppscotch-common/src/helpers/backend/mutations/MockServer.ts","lineNumber":139,"sourceCode":"      // Map the GraphQL response to frontend format\n      return {\n        ...data,\n        userUid: data.creator?.uid || \"\", // Legacy field\n        collectionID: data.collection?.id || \"\", // Legacy field\n      } as MockServer\n    },\n    (error) => (error as Error).message as UpdateMockServerError\n  )\n\nexport const deleteMockServer = (id: string) =>\n  TE.tryCatch(\n    async () => {\n      const result = await client\n        .value!.mutation(DeleteMockServerDocument, { id })\n        .toPromise()\n\n      if (result.error) {\n        throw new Error(result.error.message || \"Failed to delete mock server\")\n      }\n\n      if (!result.data) {\n        throw new Error(\"No data returned from delete mock server mutation\")\n      }\n\n      return result.data.deleteMockServer as boolean\n    },\n    (error) => (error as Error).message as DeleteMockServerError\n  )\n\n// Centralized mapper for backend GraphQL error tokens to user-facing messages.\nexport const getErrorMessage = (err: GQLError<string> | string | Error) => {\n  const t = getI18n()\n\n  // Normalize to GQLError-like shape\n  let gErr: GQLError<string> | null = null\n","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/hoppscotch/hoppscotch/blob/1acb8a3a7581e4db32ba0d529170c4669a2e1053/packages/hoppscotch-common/src/helpers/backend/mutations/MockServer.ts#L121-L157","documentation":"Thrown by deleteMockServer inside a TE.tryCatch TaskEither when the GraphQL mutation resolves with result.error but that error carries no message string. It is the fallback branch of `result.error.message || 'Failed to delete mock server'`, so it fires only when the urql client surfaces a network/GraphQL error whose message is empty or undefined. The thrown Error is immediately caught by the tryCatch error handler and re-projected as a DeleteMockServerError string, so callers see the text, not the original graphQL error object.","triggerScenarios":"Calling deleteMockServer(id) where the backend DeleteMockServerDocument mutation is rejected with an error object whose .message is falsy (e.g. an extension-only GraphQL error, an aborted network request surfaced as { error: {} }, or an auth error stripped of its message by an interceptor). Also fires if result.error is a network CombinedError whose networkError.message is empty while graphQLErrors is empty.","commonSituations":"Session expired so the backend returns an unauthenticated GraphQL error with only extensions and no message; a proxy/gateway rewrites the error body and drops `message`; urql version change where CombinedError.message becomes undefined for network-only failures; running against a dev backend that returns `errors: [{ extensions: { code: '...' } }]` with no top-level message.","solutions":["Inspect the actual result.error shape in the network tab/devtools — if it is a urql CombinedError, read graphQLErrors[0].message and networkError separately rather than relying on .message.","Re-authenticate: an empty-message error most often means the access token was rejected, so refresh the session and retry the delete.","Patch the throw to serialize the full error (`throw new Error(result.error.message || JSON.stringify(result.error) || 'Failed to delete mock server')`) so future occurrences carry diagnostics.","Check backend logs for the corresponding DeleteMockServerDocument rejection — the server side has the real reason."],"exampleFix":"// before\nif (result.error) {\n  throw new Error(result.error.message || \"Failed to delete mock server\")\n}\n\n// after\nif (result.error) {\n  const detail =\n    result.error.message ||\n    (result.error.graphQLErrors?.[0]?.message) ||\n    JSON.stringify(result.error)\n  throw new Error(`Failed to delete mock server: ${detail}`)\n}","handlingStrategy":"try-catch","validationCode":"// Before calling, confirm session is valid and the mock server exists.\nimport { flow, pipe } from 'fp-ts/function'\nimport * as TE from 'fp-ts/TaskEither'\n\nconst safeDelete = (id: string) =>\n  pipe(\n    deleteMockServer(id),\n    TE.mapLeft((msg) => ({ code: 'DELETE_MOCK_SERVER_FAILED', msg, id }))\n  )","typeGuard":"import * as E from 'fp-ts/Either'\n\nconst isMockServerError = (e: unknown): e is DeleteMockServerError =>\n  typeof e === 'string' && /mock server/i.test(e)","tryCatchPattern":"// deleteMockServer returns TE.TaskEither<DeleteMockServerError, boolean>\nconst result = await pipe(\n  deleteMockServer(id),\n  TE.match(\n    (errMsg) => { toast.error(errMsg); return false },\n  (ok) => { toast.success('Deleted'); return ok }\n  )\n)()","preventionTips":["Always consume deleteMockServer via fp-ts pipe + TE.match rather than awaiting it raw — it never rejects at the Promise level.","Refresh the session before destructive mutations.","Confirm the mock server ID exists in the current list before showing the delete action."],"tags":["graphql","urql","mock-server","error-handling","task-either"],"backgroundTag":null,"analyzedSha":"1acb8a3a7581e4db32ba0d529170c4669a2e1053","analyzedAt":"2026-08-12T11:34:52.648Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}