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.js – getLocationData): 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.js – getCountryData): 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
Bug: GeolocationEditor crashes with
TypeError: Cannot read properties of undefined (reading 'includes')when geo-data files return 404Summary
In SeaTable external apps (Universal Apps / Page Design apps), the geo-data JSON files are fetched using a
mediaUrlthat resolves to the app's own URL path, causing 404 errors. When both the primary and fallback fetches fail, thegetLocationDataandgetCountryDatafunctions return rejected promises instead of resolving gracefully. This causes the components to crash or stay frozen in a loading state.Error Stack Trace
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→ 404The geo-data URLs are constructed using
${server}${mediaUrl}geo-data/...wheremediaUrlis 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.js–getLocationData): The fallbackfetch('./geo-data/cn-location.json')has no.catch(). If it also fails (both fetches 404), the whole promise rejects, andcomponentDidMount/UNSAFE_componentWillMount's.then()never runs.Bug 2 (
index.js–getCountryData): Same issue in the fallback fetch. Additionally,const { mediaUrl = '', server = '' } = config;will throw ifconfigisnullorundefined(unlikegetLocationDatawhich usesconfig || {}).Bug 3 (pc-editor:
ProvinceEditor,ProvinceCityEditor,LocationEditor):.catch()on thegetData()call, so a rejected promise leavesisLoadingData: trueforever.this.locations.childrenis accessed without a null guard; ifdataisundefined/null, this throws.province.name.includes(...)is called without checkingprovince.namefirst; corrupt geo-data entries crash the editor.Bug 4 (mb-editor): Same missing
.catch()handlers andnullguards in the functional components.Proposed Fix
src/GeolocationEditor/index.js: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):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-safetyin 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-componentnpm6.0.116