appsmithorg/appsmith · error · FoundPromiseInSyncEvalError

Found a Promise() during evaluation. Data fields cannot exec

Error message

Found a Promise() during evaluation. Data fields cannot execute asynchronous code.

What it means

FoundPromiseInSyncEvalError thrown by the eval worker when a data-field binding returns a Promise. Data fields (Text.value, Input.defaultText, container background, etc.) are evaluated synchronously by indirectEval, so any returned Promise is unawaitable and would silently render [object Promise]. The error surfaces that the user must move the logic to an async context. The thrown error then routes through errorModifier.run alongside ActionInDataFieldErrorModifier and TypeErrorModifier.

Source

Thrown at app/client/src/workers/Evaluation/evaluate.ts:436

        isTriggerBased: isJSCollection,
      });

      Object.assign(EVAL_CONTEXT, dataTreeContext);
    }

    overrideEvalContext(EVAL_CONTEXT, context?.overrideContext);

    Object.assign(self, EVAL_CONTEXT);

    try {
      result = indirectEval(script);

      if (result instanceof Promise) {
        /**
         * If a promise is returned in data field then show the error to help understand data field doesn't await to resolve promise.
         * NOTE: Awaiting for promise will make data field evaluation slower.
         */
        throw new FoundPromiseInSyncEvalError();
      }
      // TODO: Fix this the next time the file is edited
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } catch (error: any) {
      const { errorCategory, errorMessage, rootcause } = errorModifier.run(
        error,
        { userScript: error.userScript || userScript, source: error.source },
        [ActionInDataFieldErrorModifier, TypeErrorModifier],
      );

      errors.push({
        errorMessage,
        severity: Severity.ERROR,
        raw: script,
        errorType: PropertyEvaluationErrorType.PARSE,
        originalBinding: userScript,
        kind: {
          category: errorCategory,

View on GitHub (pinned to 8cd9021c24)

Solutions

  1. Reference the query's cached result instead of calling it: {{ getApi.data }}.
  2. Move async logic into a JS object function and trigger it via an event (onPageLoad, onClick), then bind to the JS object's result property.
  3. Use the onSuccess callback of the action to refresh data the binding depends on.
  4. Avoid fetch/Promise/await inside moustache bindings entirely.

Example fix

// before — Text widget value
{{ getApi.run() }}   // returns a Promise -> error
// after
{{ getApi.data }}    // resolved data, populated after run
// or move to JS object
export default {
  async load() { this.data = await getApi.run(); }
};
// bind widget to {{ JSObject.data }}
Defensive patterns

Strategy: type-guard

Validate before calling

// Never call async code from a data field; route through a JS object
// JS object
export default {
  async load() { this.users = await getApi.run(); }
};
// widget binding uses {{ JSObject.users }}, not {{ getApi.run() }}

Type guard

function returnsPromise(v: unknown): v is Promise<unknown> {
  return v != null && typeof (v as Promise<unknown>).then === 'function';
}

Prevention

When it happens

Trigger: Binding a query directly: {{ getApi.run() }}; calling a JS object method that is async or returns a Promise; using fetch/await/Promise.then inside a data field; referencing a library function that returns a Promise.

Common situations: New users referencing the query function instead of its result; migrating from a JS object where async was fine into a data field; calling moment().then() or lodash debounce in a binding.

Related errors


AI-assisted analysis of appsmithorg/appsmith@8cd9021c24 (2026-08-12). Data as JSON: /api/errors/42f77fdd6d97becc. Report an issue: GitHub.