A limit aborting the table request left the filter picker with no variables, so the "please filter and try again" advice could not be acted on: the picker's list came from the columns that arrived with the table, and there was no table. The list now falls back to public/getcols, which reads the column metadata without the rows. The normal path is unchanged - the service is only called when the caller has no columns to hand - so nothing extra is requested for a table that loaded. - SasStoreService.getCols() calls public/getcols and returns cols. - SasStoreService.setQueryVariablesFromTable() takes the columns the caller already has and reaches for the service only when they are empty. - editor openQb() and viewboxes openFilter() use it (the viewer's filter is reachable after a VIEW abort, the editor's after an EDIT abort). - public/getcols.sas keeps ddtype (already computed, dropped by the keep) and excludes the temporal columns exactly as the editor does, so the fallback list matches the table's own. - New mock public/getcols.js mirrors the service. Verified: the mock's list matches editors/getdata for every fixture except the aborting one (MPE_X_SEARCH: getdata 0 cols, getcols 9), and a new Cypress case in row-cell-limits.cy.ts aborts a too-big EDIT, opens the filter and asserts all nine columns are offered. 89 Cypress tests green across the six affected specs.