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
- 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.
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
- 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.
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
- Failed to delete mock server log
- Failed to update mock server
- No data returned from delete mock server mutation
- Failed to fetch mock server logs
- No data returned from deleteMockServerLog
AI-assisted analysis of hoppscotch/hoppscotch@1acb8a3a75 (2026-08-12).
Data as JSON: /api/errors/f8094d5a3fe80a1f.
Report an issue: GitHub.