Skip to content

fix: GeolocationEditor crashes when geo-data files return 404 (unhandled promise rejection + missing null guards) #437

@Laqoore

Description

@Laqoore

Bug: GeolocationEditor crashes with TypeError: Cannot read properties of undefined (reading 'includes') when geo-data files return 404

Summary

In SeaTable external apps (Universal Apps / Page Design apps), the geo-data JSON files are fetched using a mediaUrl that resolves to the app's own URL path, causing 404 errors. When both the primary and fallback fetches fail, the getLocationData and getCountryData functions return rejected promises instead of resolving gracefully. This causes the components to crash or stay frozen in a loading state.

Error Stack Trace

TypeError: Cannot read properties of undefined (reading "includes")
  at Array.filter
  at DE.render (main.js?version=6.1.48:1:3272279)
  at Os (main.js?version=6.1.48:1:8004537)
  ...

404 Errors Observed

In a SeaTable external app, the following 404s are logged:

  • /external-apps/<uuid>/geo-data/en-region-location.json → 404
  • /external-apps/<uuid>/geo-data/cn-location.json → 404
  • /external-apps/<uuid>/geo-data/cn-region-location.json → 404

The geo-data URLs are constructed using ${server}${mediaUrl}geo-data/... where mediaUrl is set to the external app path instead of SeaTable's /media/ directory. The ./geo-data/ fallback also resolves to the same app path.

Root Causes

Bug 1 (index.jsgetLocationData): The fallback fetch('./geo-data/cn-location.json') has no .catch(). If it also fails (both fetches 404), the whole promise rejects, and componentDidMount/UNSAFE_componentWillMount's .then() never runs.

Bug 2 (index.jsgetCountryData): Same issue in the fallback fetch. Additionally, const { mediaUrl = '', server = '' } = config; will throw if config is null or undefined (unlike getLocationData which uses config || {}).

Bug 3 (pc-editor: ProvinceEditor, ProvinceCityEditor, LocationEditor):

  • No .catch() on the getData() call, so a rejected promise leaves isLoadingData: true forever.
  • this.locations.children is accessed without a null guard; if data is undefined/null, this throws.
  • province.name.includes(...) is called without checking province.name first; corrupt geo-data entries crash the editor.

Bug 4 (mb-editor): Same missing .catch() handlers and null guards in the functional components.

Proposed Fix

src/GeolocationEditor/index.js:

-    const { server = '', mediaUrl = '' } = config || {};
+    const { server = '', mediaUrl = '' } = config || {};  // already correct in getLocationData
     return fetch(primary).then(res => res.json())
       .catch(() => {
-        return fetch('./geo-data/cn-location.json').then(res => res.json());
+        return fetch('./geo-data/cn-location.json').then(res => res.json()).catch(() => null);
       });

-    const { mediaUrl = '', server = '' } = config;       // BUG: throws if config is null
+    const { mediaUrl = '', server = '' } = config || {};
     ...
       .catch(() => {
-        return fetch(`./geo-data/${geoFileName}.json`).then(res => res.json());
+        return fetch(`./geo-data/${geoFileName}.json`).then(res => res.json()).catch(() => null);
       })

src/GeolocationEditor/pc-editor/province-editor.js (and ProvinceCityEditor, LocationEditor):

     this.props.getData().then(data => {
-      this.locations = data;
-      this.filteredProvince = this.locations.children;
+      this.locations = data || {};
+      this.filteredProvince = this.locations.children || [];
       this.setState({ isLoadingData: false });
+    }).catch(() => {
+      this.locations = {};
+      this.filteredProvince = [];
+      this.setState({ isLoadingData: false });
     });

src/GeolocationEditor/pc-editor/location-editor.js (initLocationSelecting):

-    let selectedProvince = this.locations.children.find((province) => {
-      return value.province && value.province.length > 0 && province.name.includes(value.province);
+    let selectedProvince = (this.locations.children || []).find((province) => {
+      return value.province && value.province.length > 0 && province.name && province.name.includes(value.province);
     });

src/GeolocationEditor/mb-editor/index.js (transLocationData/transCountryData):

 const transLocationData = (data) => {
+  if (!data) return [];
   if (Object.prototype.toString.call(data) === '[object Object]') {
     ...
   }
-  return data.children;
+  return data.children || [];
 };

 const transCountryData = (data) => {
+  if (!data) return [];
   let _data = [];

A complete fix is available as branch fix/geo-data-fetch-null-safety in the fork at https://github.com/Laqoore/dtable-ui-component (if the fork can be created) or as a patch file on request.

SeaTable Version

SeaTable cloud main.js?version=6.1.48, dtable-ui-component npm 6.0.116

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions