{"record":{"id":"1b978475930aad08","repo":"actualbudget/actual","slug":"geolocation-error","errorCode":null,"errorMessage":"Geolocation error:","messagePattern":"Geolocation error:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/desktop-client/src/payees/location-service.ts","lineNumber":37,"sourceCode":"    private geolocation: GeolocationAdapter,\n    private apiClient: LocationApiClient,\n  ) {}\n\n  async getCurrentPosition(): Promise<LocationCoordinates> {\n    // Return cached position if it's recent\n    if (\n      this.currentPosition &&\n      Date.now() - this.lastLocationTime < this.CACHE_DURATION\n    ) {\n      return this.currentPosition;\n    }\n\n    try {\n      this.currentPosition = await this.geolocation.getCurrentPosition();\n      this.lastLocationTime = Date.now();\n      return this.currentPosition;\n    } catch (error) {\n      console.warn('Geolocation error:', error);\n      throw error;\n    }\n  }\n\n  async savePayeeLocation(\n    payeeId: string,\n    coordinates: LocationCoordinates,\n  ): Promise<string> {\n    try {\n      return await this.apiClient.saveLocation(payeeId, coordinates);\n    } catch (error) {\n      console.error('Failed to save payee location:', error);\n      throw error;\n    }\n  }\n\n  async getPayeeLocations(payeeId: string): Promise<PayeeLocationEntity[]> {\n    try {","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/desktop-client/src/payees/location-service.ts#L19-L55","documentation":"A console.warn plus re-throw in the PayeesLocationService getCurrentPosition (packages/desktop-client/src/payees/location-service.ts). When the underlying geolocation provider (navigator.geolocation) fails — permission denied, timeout, or unavailable position — the service logs the raw error and propagates it to callers (position/position1/position2 lookups used to tag payee locations).","triggerScenarios":"Calling getCurrentPosition() when the browser Geolocation API returns a PositionError (code 1 permission-denied, 2 position-unavailable, 3 timeout), or when geolocation is not supported/not secure-context.","commonSituations":"User denied the location permission prompt; app served over plain HTTP (geolocation blocked); GPS/Wi-Fi positioning unavailable indoors; geolocation timeout on slow devices; desktop app window without location permission.","solutions":["Request geolocation permission (Permissions API) before calling and show an explanatory prompt","Serve the app over HTTPS / configure Electron permission handlers to allow geolocation","Increase the geolocation timeout / enable high-accuracy options in the provider","Catch the rethrown error at call sites and proceed without tagging payee location"],"exampleFix":"// before\nconst pos = await locationService.getCurrentPosition();\n// after\nlet pos;\ntry {\n  pos = await locationService.getCurrentPosition();\n} catch {\n  pos = null; // proceed without location tagging\n}","handlingStrategy":"try-catch","validationCode":"const perm = await navigator.permissions?.query({ name: 'geolocation' });\nif (perm && perm.state === 'denied') console.warn('Geolocation unavailable: permission denied');","typeGuard":"function isGeolocationError(e: unknown): e is GeolocationPositionError {\n  return typeof e === 'object' && e !== null && 'code' in e && 'PERMISSION_DENIED' in GeolocationPositionError;\n}","tryCatchPattern":"try {\n  const pos = await locationService.getCurrentPosition();\n} catch (e) {\n  if (isGeolocationError(e) && e.code === e.PERMISSION_DENIED) showPermissionInstructions();\n  else proceedWithoutLocation();\n}","preventionTips":["Check Permissions API state before requesting position","Only call geolocation from secure contexts (HTTPS)","Provide a graceful no-location path for payee tagging","Set sane timeout/maximumAge options on the geolocation call"],"tags":["geolocation","browser-api","permissions"],"backgroundTag":"geolocation-permission-denied","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}