{"record":{"id":"c135e00fc2a8be65","repo":"Budibase/budibase","slug":"no-table-id-supplied","errorCode":null,"errorMessage":"No table ID supplied","messagePattern":"No table ID supplied","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server/src/sdk/workspace/tables/external/index.ts","lineNumber":102,"sourceCode":"\n      if (oldColumn && column.timeOnly !== oldColumn.timeOnly) {\n        throw new Error(\n          `Column \"${key}\" can not change from time to datetime or viceversa.`\n        )\n      }\n    }\n  }\n}\n\nfunction getDatasourceId(table: Table) {\n  if (!table) {\n    throw new Error(\"No table supplied\")\n  }\n  if (table.sourceId) {\n    return table.sourceId\n  }\n  if (!table._id) {\n    throw new Error(\"No table ID supplied\")\n  }\n  return breakExternalTableId(table._id).datasourceId\n}\n\nexport async function create(table: WithoutDocMetadata<Table>) {\n  const datasourceId = getDatasourceId(table)\n\n  const tableToCreate = { ...table, created: true }\n  try {\n    const result = await save(datasourceId!, tableToCreate)\n    return result.table\n  } catch (err: any) {\n    if (err instanceof Error) {\n      throw new HTTPError(err.message, 400)\n    } else {\n      throw new HTTPError(err?.message || err, err.status || 500)\n    }\n  }","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/tables/external/index.ts#L84-L120","documentation":"getDatasourceId resolves the datasource ID from a table for external (SQL) datasources. It uses table.sourceId if present, otherwise derives the datasource ID by parsing the table's _id via breakExternalTableId. If the table has neither a sourceId nor an _id, there is no way to identify the datasource, so it throws.","triggerScenarios":"Calling getDatasourceId(table) (directly or via create/save of an external table) with a table object that has no sourceId and no _id — e.g. a newly constructed table object not yet persisted, or a partially hydrated table from an API response.","commonSituations":"Building a new external table without first persisting it; passing a table-like object from a client request that omitted _id; deserialization dropping metadata fields (_id) from the table document.","solutions":["Ensure the table passed to create/save includes its _id (fetch the table first via tables.get if updating)","Set table.sourceId to the datasource ID explicitly when constructing external tables","Only call save/create with tables loaded through the SDK getters, which populate _id and sourceId"],"exampleFix":"// before\nawait tables.external.create({ name: \"users\", schema, primary: [\"id\"] })\n// after\nconst dsTable = await tables.external.get(datasourceId, \"users\")\ndsTable.schema.newColumn = fieldSchema\nawait tables.external.create(dsTable)","handlingStrategy":"validation","validationCode":"if (!table.sourceId && !table._id) throw new Error(\"Table requires _id or sourceId before save\")","typeGuard":"function hasTableIdentifier(table: Table): table is Table & ({ _id: string } | { sourceId: string }) {\n  return typeof table.sourceId === \"string\" || typeof table._id === \"string\"\n}","tryCatchPattern":"try {\n  await tables.external.create(table)\n} catch (err) {\n  if (err.message === \"No table ID supplied\") {\n    // re-fetch table by name to get _id, then retry\n  }\n}","preventionTips":["Always load external tables via SDK getters before mutating and saving","Set sourceId explicitly when constructing external table objects","Never save hand-built table objects without an _id"],"tags":["external-datasource","missing-identifier","validation"],"backgroundTag":"missing-required-identifier","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}