BUG : Metadata API (_grist_Tables_column) Reports Incorrect isFormula: true for Non-Formula Columns

Problem Description:

When fetching column metadata using grist.docApi.fetchTable(‘_grist_Tables_column’) within a Custom Widget, the data returned in the isFormula array incorrectly reports true for several columns that are configured as standard ‘Data’ columns (not ‘Formula’ or ‘Trigger Formula’) in the Grist user interface.

Simultaneously, the corresponding entry in the formula array for these same columns is an empty string (“”), which is consistent with them not being formula columns.

This discrepancy between the Grist UI configuration and the API-reported isFormula flag causes issues for widgets that rely on this flag to determine column editability or behavior.

Steps to Reproduce:

  1. Create a Grist Document: Set up a table (e.g., MyTable) with various column types, including standard types like Text, Choice, Numeric, Date, and Ref:[AnotherTable]. Ensure these columns are set to “Data” columns in the column configuration panel (i.e., no formula is defined, and they are not Trigger Formulas).

  2. Create a Custom Widget: Add a Custom Widget section linked to MyTable.

  3. Fetch Metadata: Use the following code snippet (or similar) within the widget’s script to fetch and log the relevant metadata:

grist.ready({ requiredAccess: 'full' });

(async function() {
    try {
        console.log("Fetching metadata _grist_Tables_column...");
        const metaTable = await grist.docApi.fetchTable("_grist_Tables_column");
        console.log("Metadata fetched.");

        // Find the numeric ID of the linked table
        const mainTableName = await grist.selectedTable.getTableId(); // Assumes this works correctly now
        const tablesMeta = await grist.docApi.fetchTable('_grist_Tables');
        let mainTableNumericId = null;
        for (let i = 0; i < tablesMeta.tableId.length; i++) {
            if (tablesMeta.tableId[i] === mainTableName) {
                mainTableNumericId = tablesMeta.id[i];
                break;
            }
        }

        if (!mainTableNumericId) {
            console.error("Could not find numeric ID for table:", mainTableName);
            return;
        }
        console.log(`Processing metadata for Table ID: ${mainTableNumericId} (Name: ${mainTableName})`);

        // Extract relevant columns' metadata
        const tableKey = metaTable.parentId ? "parentId" : "tableId";
        const colKey = metaTable.colId ? "colId" : "columnId";
        const typeKey = "type";
        const formulaKey = "formula";
        const isFormulaKey = "isFormula";
        const labelKey = "label";

        const columnsData = [];
        if (metaTable[tableKey] && metaTable[colKey]) {
            for (let i = 0; i < metaTable[colKey].length; i++) {
                if (String(metaTable[tableKey][i]) === String(mainTableNumericId)) {
                    columnsData.push({
                        index: i,
                        colId: metaTable[colKey][i],
                        label: metaTable[labelKey]?.[i] || metaTable[colKey][i],
                        type: metaTable[typeKey]?.[i] || 'N/A',
                        formulaContent: metaTable[formulaKey]?.[i] ?? null, // Get actual formula
                        isFormulaFlag: metaTable[isFormulaKey]?.[i] ?? null // Get the flag value
                    });
                }
            }
        }
        console.table(columnsData); // Display extracted data in console table

    } catch(e) {
        console.error("Error fetching or processing metadata:", e);
    }
})();

content_copydownload

Use code with caution.JavaScript

  1. Observe Console Output: Examine the table logged in the developer console. Find rows corresponding to standard data columns (like simple Text or Choice columns).

  2. Compare: Note the value shown in the isFormulaFlag column for these rows and compare it with the actual column configuration in the Grist UI.

Observed Behavior:

For several standard data columns (e.g., a Text column named CPF, a Choice column named Empresa), the isFormulaFlag logged from the _grist_Tables_column metadata is true, while the formulaContent is “” (empty string) or null. The Grist UI confirms these columns are not set as Formula or Trigger Formula columns.

(Optional: You can refer to the metadata dump provided earlier, specifically showing colId: “CPF”, type: “Text”, isFormula: true, formula: “” for parentId: 8)

Expected Behavior:

The isFormula flag in the _grist_Tables_column metadata should accurately reflect the column’s configuration in the Grist UI. For standard data columns (not Formula or Trigger Formula), the isFormula flag should be false.

Workaround:

A functional workaround within the widget is to ignore the potentially unreliable isFormula flag and instead determine if a column is a formula by checking if the formula field has non-empty content:
const isActuallyFormula = formulaContent !== null && String(formulaContent).trim() !== ‘’;

Impact:

Custom widgets relying on the isFormula flag for determining column behavior (e.g., enabling/disabling editing in custom UIs) may function incorrectly, leading to a poor user experience where fields appear non-editable when they should be. This requires widget developers to implement workarounds based on checking the formula content instead.

here, I mounted the data in an Excel table… look the amount of isFormula columns marked with “true”, while column “formula” shows no formula at all