Freika/dawarich · warning · Error

response.error

Error message

response.error

What it means

A defensive check in SearchManager after LocationSearchService.createVisit resolves. createVisit already throws on any non-OK response, and the success payload is Api::VisitSerializer output (id, name, latitude, ...) with no top-level 'error' key, so this branch is only reachable when the server answers 2xx yet embeds an 'error' field - i.e. an API contract change or an intermediary rewriting responses. In the current codebase it is effectively dead-path defense.

Source

Thrown at app/javascript/maps_maplibre/utils/search_manager.js:646

    submitBtn.disabled = true
    submitText.classList.add("hidden")
    spinner.classList.remove("hidden")

    try {
      const formData = new FormData(form)
      const visitData = {
        name: formData.get("name"),
        latitude: parseFloat(formData.get("latitude")),
        longitude: parseFloat(formData.get("longitude")),
        started_at: formData.get("started_at"),
        ended_at: formData.get("ended_at"),
        status: "confirmed",
      }

      const response = await this.service.createVisit(visitData)

      if (response.error) {
        throw new Error(response.error)
      }

      // Success - close modal and show success message
      const modalToggle = modal.querySelector(".modal-toggle")
      modalToggle.checked = false
      setTimeout(() => modal.remove(), 300)

      // Show success notification
      this.showSuccessNotification(translate("visits.created_without_name"))

      // Dispatch custom event for other components to react
      document.dispatchEvent(
        new CustomEvent("visit:created", {
          detail: {
            visit: response,
            coordinates: [visitData.longitude, visitData.latitude],
          },
        }),

View on GitHub (pinned to 97fad417c5)

Solutions

  1. Inspect the actual 200 response body in the Network tab to see what populated response.error
  2. Confirm the frontend bundle and backend version match (stale cached JS after a deploy is the usual cause)
  3. If the API genuinely adopted an error-in-200 envelope, update LocationSearchService to detect it centrally instead of per-callsite
  4. Remove the check or keep it as an assertion if the contract is confirmed to never return error on 2xx
Defensive patterns

Strategy: type-guard

Type guard

/** True when a 2xx body carries an API error envelope. */
function isErroredPayload(payload) {
  return (
    payload !== null &&
    typeof payload === 'object' &&
    typeof payload.error === 'string' &&
    payload.error.length > 0
  )
}

Try / catch

try {
  const response = await this.service.createVisit(visitData)
  if (isErroredPayload(response)) {
    throw new Error(response.error)
  }
  // success path
} catch (error) {
  this.showErrorNotification(error.message)
}

Prevention

When it happens

Trigger: A 200 response from /api/v1/visits whose JSON body contains a truthy error key - e.g. after a future API change returning {error: ..., visit: ...}, a proxy injecting an error envelope, or a misrouted request hitting a different endpoint that uses error-style envelopes.

Common situations: API contract drift after upgrading Dawarich while the JS bundle is stale (or vice versa), a debugging middleware that appends error fields to responses, integration tests stubbing fetch with an error envelope and a 200 status.

Related errors


AI-assisted analysis of Freika/dawarich@97fad417c5 (2026-08-21). Data as JSON: /api/errors/a3d2e2b97eeeafd4. Report an issue: GitHub.