{"record":{"id":"c083a00820f7bb34","repo":"apache/superset","slug":"unknown-error","errorCode":null,"errorMessage":"Unknown Error","messagePattern":"Unknown Error","errorType":"http","errorClass":"SupersetApiError","httpStatus":null,"severity":"error","filePath":"superset-frontend/packages/superset-ui-core/src/query/api/v1/handleError.ts","lineNumber":42,"sourceCode":"\nexport type ErrorInput = string | Error | Response | SupersetApiErrorPayload;\n\n/**\n * Handle API request errors, convert to consistent Superset API error.\n * @param error the catched error from SupersetClient.request(...)\n */\nexport default async function handleError(error: ErrorInput): Promise<never> {\n  // already a Superset error\n  if (error instanceof SupersetApiError) {\n    throw error;\n  }\n  // string is the error message itself\n  if (typeof error === 'string') {\n    throw new SupersetApiError({ message: error });\n  }\n  // JS errors, normally happens before request was sent\n  if (error instanceof Error) {\n    throw new SupersetApiError({\n      message: error.message || 'Unknown Error',\n      originalError: error,\n    });\n  }\n\n  let errorJson;\n  let originalError;\n  let errorMessage = 'Unknown Error';\n  let status: number | undefined;\n  let statusText: string | undefined;\n\n  // catch HTTP errors\n  if (error instanceof Response) {\n    const { status: responseStatus, statusText: responseStatusText } = error;\n    status = responseStatus;\n    statusText = responseStatusText;\n    errorMessage = `${status} ${statusText}`;\n    try {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset-frontend/packages/superset-ui-core/src/query/api/v1/handleError.ts#L24-L60","documentation":"Raised by extra_validator (superset/databases/schemas.py:273) when the Database API extra field is non-empty but not parseable JSON. extra carries connection tuning options (engine_params, metadata_params, schema_cache_timeout, etc.) as a JSON string; marshmallow validation fails with HTTP 400 and the underlying json.JSONDecodeError message before any DB engine is constructed.","triggerScenarios":"POST/PUT /api/v1/database with extra built via Python repr or f-string templating that breaks quoting; extra containing NaN/Infinity literals (invalid JSON); copy-pasting the YAML form of extra from superset config docs directly into the API payload.","commonSituations":"Converting a config-file TSQL/CATALOGS-style extra dict to the REST API format and forgetting json.dumps; injecting secrets into extra via string concatenation that leaves unescaped quotes; version upgrades where extra keys changed shape and scripts send hand-built JSON strings.","solutions":["Build extra as a dict and serialize with json.dumps() instead of string concatenation or repr()","Lint the payload locally: json.loads(extra) must succeed before sending","Check the error's %(msg)s detail — it names the line/column of the first JSON syntax error"],"exampleFix":"// before (frontend)\nbody.extra = `{ engine_params: { pool_size: 5 } }`;  // unquoted keys -> 400\n\n// after\nbody.extra = JSON.stringify({ engine_params: { pool_size: 5 } });","handlingStrategy":"validation","validationCode":"import json\n\nextra_obj = {\"engine_params\": {\"pool_size\": 5}}\npayload[\"extra\"] = json.dumps(extra_obj)  # never hand-built strings\njson.loads(payload[\"extra\"])  # assert round-trip","typeGuard":"function isExtraJson(extra: string): boolean {\n  try { JSON.parse(extra); return true; } catch { return false; }\n}","tryCatchPattern":"if resp.status_code == 400 and \"cannot be decoded by JSON\" in resp.text:\n    # resp body carries the JSONDecodeError position; fix the payload at that offset","preventionTips":["Construct extra as a dict and serialize once","Beware NaN/Infinity and single quotes — valid Python literals, invalid JSON","After upgrades, re-read the Database API schema for extra key changes"],"tags":["superset","rest-api","json","validation","database-connections"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}