hoppscotch/hoppscotch · error · Error

Failed to delete mock server

Error message

Failed to delete mock server

What it means

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.

Source

Thrown at packages/hoppscotch-common/src/helpers/backend/mutations/MockServer.ts:139

      // Map the GraphQL response to frontend format
      return {
        ...data,
        userUid: data.creator?.uid || "", // Legacy field
        collectionID: data.collection?.id || "", // Legacy field
      } as MockServer
    },
    (error) => (error as Error).message as UpdateMockServerError
  )

export const deleteMockServer = (id: string) =>
  TE.tryCatch(
    async () => {
      const result = await client
        .value!.mutation(DeleteMockServerDocument, { id })
        .toPromise()

      if (result.error) {
        throw new Error(result.error.message || "Failed to delete mock server")
      }

      if (!result.data) {
        throw new Error("No data returned from delete mock server mutation")
      }

      return result.data.deleteMockServer as boolean
    },
    (error) => (error as Error).message as DeleteMockServerError
  )

// Centralized mapper for backend GraphQL error tokens to user-facing messages.
export const getErrorMessage = (err: GQLError<string> | string | Error) => {
  const t = getI18n()

  // Normalize to GQLError-like shape
  let gErr: GQLError<string> | null = null

View on GitHub (pinned to 1acb8a3a75)

Solutions

  1. 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.
  2. Re-authenticate: an empty-message error most often means the access token was rejected, so refresh the session and retry the delete.
  3. 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.
  4. Check backend logs for the corresponding DeleteMockServerDocument rejection — the server side has the real reason.

Example fix

// before
if (result.error) {
  throw new Error(result.error.message || "Failed to delete mock server")
}

// after
if (result.error) {
  const detail =
    result.error.message ||
    (result.error.graphQLErrors?.[0]?.message) ||
    JSON.stringify(result.error)
  throw new Error(`Failed to delete mock server: ${detail}`)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before calling, confirm session is valid and the mock server exists.
import { flow, pipe } from 'fp-ts/function'
import * as TE from 'fp-ts/TaskEither'

const safeDelete = (id: string) =>
  pipe(
    deleteMockServer(id),
    TE.mapLeft((msg) => ({ code: 'DELETE_MOCK_SERVER_FAILED', msg, id }))
  )

Type guard

import * as E from 'fp-ts/Either'

const isMockServerError = (e: unknown): e is DeleteMockServerError =>
  typeof e === 'string' && /mock server/i.test(e)

Try / catch

// deleteMockServer returns TE.TaskEither<DeleteMockServerError, boolean>
const result = await pipe(
  deleteMockServer(id),
  TE.match(
    (errMsg) => { toast.error(errMsg); return false },
  (ok) => { toast.success('Deleted'); return ok }
  )
)()

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hoppscotch/hoppscotch@1acb8a3a75 (2026-08-12). Data as JSON: /api/errors/f8094d5a3fe80a1f. Report an issue: GitHub.