{"record":{"id":"0ca6ab3e454f50ba","repo":"apache/superset","slug":"bad-spatial-key","errorCode":null,"errorMessage":"Bad spatial key","messagePattern":"Bad spatial key","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"superset-frontend/plugins/preset-chart-deckgl/src/layers/spatialUtils.ts","lineNumber":75,"sourceCode":"  color_scheme?: string;\n  color_scheme_type?: string;\n  color_breakpoints?: number[];\n  default_breakpoint_color?: string;\n  tooltip_contents?: unknown[];\n  tooltip_template?: string;\n  color_picker?: string;\n}\n\nexport interface SpatialPoint {\n  position: [number, number];\n  weight: number;\n  extraProps?: Record<string, unknown>;\n  [key: string]: unknown;\n}\n\nexport function getSpatialColumns(spatial: SpatialConfiguration): string[] {\n  if (!spatial || !spatial.type) {\n    throw new Error('Bad spatial key');\n  }\n\n  switch (spatial.type) {\n    case 'latlong':\n      if (!spatial.lonCol || !spatial.latCol) {\n        throw new Error(\n          'Longitude and latitude columns are required for latlong type',\n        );\n      }\n      return [spatial.lonCol, spatial.latCol];\n    case 'delimited':\n      if (!spatial.lonlatCol) {\n        throw new Error(\n          'Longitude/latitude column is required for delimited type',\n        );\n      }\n      return [spatial.lonlatCol];\n    case 'geohash':","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset-frontend/plugins/preset-chart-deckgl/src/layers/spatialUtils.ts#L57-L93","documentation":"Thrown by getSpatialColumns in the deck.gl layers' spatialUtils when the spatial configuration object is null/undefined or lacks a type field. The type discriminator ('latlong' | 'delimited' | 'geohash') selects which column fields to read; without it the function cannot map the config to query columns and rejects the input immediately.","triggerScenarios":"Calling getSpatialColumns (directly or via buildSpatialQuery / Arc / Scatter buildQuery) with undefined spatial, an empty object, or a config whose 'type' key is missing — e.g. partially deserialized form params or a hand-built spatial object.","commonSituations":"Saved chart params where spatial serialized as {} after a control reset; imports from older Superset versions with a different spatial schema; code that constructs spatial configs conditionally and skips setting type.","solutions":["Re-open the chart's spatial control in Explore and pick an encoding (latlong/delimited/geohash) so type is written into the config.","If building the config in code, always set type alongside the column fields.","Repair stale params via the chart API: PUT /api/v1/chart/{id} with corrected params JSON."],"exampleFix":"// before\ngetSpatialColumns({ lonCol: 'lon', latCol: 'lat' }); // no type -> throws\n\n// after\ngetSpatialColumns({ type: 'latlong', lonCol: 'lon', latCol: 'lat' });","handlingStrategy":"type-guard","validationCode":"if (!spatial?.type) {\n  throw new Error('Spatial config missing type');\n}\ngetSpatialColumns(spatial);","typeGuard":"const isSpatialConfig = (s: unknown): s is SpatialConfiguration =>\n  s != null && typeof s === 'object' && typeof (s as SpatialConfiguration).type === 'string';","tryCatchPattern":"try { getSpatialColumns(spatial); } catch (e) { if (e.message === 'Bad spatial key') resetSpatialControl(); else throw e; }","preventionTips":["Always set type when constructing spatial configs","Treat empty spatial objects from stale params as invalid and re-prompt"],"tags":["deckgl","spatial","validation","discriminator"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}