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
- Read data.error in the console - it carries the exact Visits::Create failure reason
- Check for an existing visit at nearly the same place/time before creating (duplicate visit is the most common 422)
- Validate name, latitude, longitude, started_at, ended_at are present and numeric/parseable client-side
- Confirm the apiKey given to LocationSearchService is current
- 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
- Check the ok status before calling response.json() so non-JSON 401/500 pages fail with a clear message
- Validate the duplicate case client-side (same place/time) before POSTing
- Keep the console.error in the service but rethrow - swallowing here hides the cause from UI handlers
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
- errorData.error || `Failed to ${isEdit ? "update" : "create"
- name
- latitude
- longitude
- Failed to fetch points: ${response.statusText}
AI-assisted analysis of Freika/dawarich@97fad417c5 (2026-08-21).
Data as JSON: /api/errors/63150474ce1042b0.
Report an issue: GitHub.