{"record":{"id":"120b833e67773431","repo":"Budibase/budibase","slug":"view-name-is-required","errorCode":null,"errorMessage":"View name is required","messagePattern":"View name is required","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/builder/src/stores/builder/views.ts","lineNumber":58,"sourceCode":"      {\n        selectedViewName: null,\n      },\n      makeDerivedStore\n    )\n\n    this.select = this.select.bind(this)\n  }\n\n  select = (name: string) => {\n    this.store.update(state => ({\n      ...state,\n      selectedViewName: name,\n    }))\n  }\n\n  delete = async (view: View) => {\n    if (!view.name) {\n      throw new Error(\"View name is required\")\n    }\n    await API.deleteView(view.name)\n\n    // Update tables\n    tables.update(state => {\n      const table = state.list.find(table => table._id === view.tableId)\n      if (table?.views && view.name) {\n        delete table.views[view.name]\n      }\n      return { ...state }\n    })\n  }\n\n  save = async (view: View & { originalName?: string }) => {\n    if (!view.name) {\n      throw new Error(\"View name is required\")\n    }\n","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/builder/src/stores/builder/views.ts#L40-L76","documentation":"ViewsStore.delete deletes a view by its name via API.deleteView(view.name). Since the view name is the view's identifier, deleting a view without a name is invalid, so the store throws before making the request.","triggerScenarios":"Calling views.delete(view) with a View object lacking a name property — e.g. a partial view object, a table-level placeholder, or a view constructed locally in code.","commonSituations":"Passing the wrong object type (a table instead of a view); deserialized view data missing name; iterating over a mixed list of tables and views; typo'd field (viewName vs name).","solutions":["Ensure the view object passed comes from the views store or a full API fetch including name","Check you are not passing a table object where a view is expected","If the view name is dynamic, validate it is a non-empty string before calling delete","Guard the call: if (!view?.name) return before invoking delete"],"exampleFix":"// before\nawait views.delete(partialView)\n// after\nif (!partialView?.name) return\nawait views.delete(partialView)","handlingStrategy":"validation","validationCode":"if (typeof view?.name !== \"string\" || !view.name.trim()) {\n  throw new Error(\"Cannot delete a view without a name\")\n}","typeGuard":"const isNamedView = (v: View): v is View & { name: string } =>\n  typeof v.name === \"string\" && v.name.trim().length > 0","tryCatchPattern":"try {\n  await views.delete(view)\n} catch (e) {\n  if (e.message === \"View name is required\") {\n    console.warn(\"View object missing name — skipping delete\")\n  } else throw e\n}","preventionTips":["Fetch views via the store/API so name is always populated","Don't pass table objects where views are expected","Validate name before any view mutation (save/delete)","Use the isNamedView guard in shared helpers"],"tags":["builder","views","missing-name","validation"],"backgroundTag":"missing-required-identifier","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}