Freika/dawarich · error · Error

Failed to create visit

Error message

Failed to create visit

What it means

LocationSearchService.createVisit POSTs to /api/v1/visits with Bearer auth and throws data.error (set by Api::V1::VisitsController to the Visits::Create service error, e.g. 'Failed to create visit: duplicate visit'), falling back to data.message, then to the generic string. Because response.json() runs before the !response.ok check, a non-JSON body (401 HTML page) actually throws an earlier SyntaxError, not this message - this message fires only for JSON error bodies.

Source

Thrown at app/javascript/maps_maplibre/services/location_search_service.js:108

  }

  /**
   * Create a new visit
   * @param {Object} visitData - Visit data
   * @returns {Promise<Object>} Created visit
   */
  async createVisit(visitData) {
    try {
      const response = await fetch("/api/v1/visits", {
        method: "POST",
        headers: this.baseHeaders,
        body: JSON.stringify({ visit: visitData }),
      })

      const data = await response.json()

      if (!response.ok) {
        throw new Error(data.error || data.message || "Failed to create visit")
      }

      return data
    } catch (error) {
      console.error("LocationSearchService: Create visit error:", error)
      throw error
    }
  }
}

View on GitHub (pinned to 97fad417c5)

Solutions

  1. Read data.error in the console - it carries the exact Visits::Create failure reason
  2. Check for an existing visit at nearly the same place/time before creating (duplicate visit is the most common 422)
  3. Validate name, latitude, longitude, started_at, ended_at are present and numeric/parseable client-side
  4. Confirm the apiKey given to LocationSearchService is current
  5. Move the response.json() call after the !response.ok check so non-JSON error pages fail with a clear message

Example fix

// before
const data = await response.json()
if (!response.ok) {
  throw new Error(data.error || data.message || 'Failed to create visit')
}

// after
if (!response.ok) {
  const data = await response.json().catch(() => ({}))
  throw new Error(data.error || data.message || `Failed to create visit (HTTP ${response.status})`)
}
const data = await response.json()
Defensive patterns

Strategy: try-catch

Validate before calling

function isValidVisitData(v) {
  return (
    typeof v.name === 'string' && v.name.trim() !== '' &&
    Number.isFinite(v.latitude) && v.latitude >= -90 && v.latitude <= 90 &&
    Number.isFinite(v.longitude) && v.longitude >= -180 && v.longitude <= 180 &&
    !Number.isNaN(Date.parse(v.started_at)) &&
    !Number.isNaN(Date.parse(v.ended_at))
  )
}

Try / catch

try {
  const visit = await service.createVisit(visitData)
  return visit
} catch (error) {
  console.error('LocationSearchService: Create visit error:', error)
  throw error // let the caller decide how to notify the user
}

Prevention

When it happens

Trigger: POST /api/v1/visits from the map's 'create visit at location' flow where the visit duplicates an existing one at the same place/time (RecordNotUnique), Place.create! fails validation (blank name, out-of-range coordinates), started_at cannot be parsed, or the endpoint returns a 422 JSON body without error/message keys.

Common situations: Clicking 'create visit' twice on the same spot within 100m and same started_at (duplicate visit), expired Bearer key in baseHeaders, user-submitted coordinates outside latitude/longitude bounds, server returning an unexpected JSON envelope after an API version change.

Related errors


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