meteor/meteor · error · Error

Can't make a blocking HTTP call from the client; callback re

Error message

Can't make a blocking HTTP call from the client; callback required.

What it means

Meteor's HTTP.call on the client is asynchronous only — it cannot block the browser. The library requires a callback as the third or fourth argument; omitting it raises this error. This is a hard client-side restriction, not a deprecation.

Source

Thrown at packages/deprecated/http/httpcall_client.js:37

 * @param {Number} options.timeout Maximum time in milliseconds to wait for the request before failing.  There is no timeout by default.
 * @param {Boolean} options.followRedirects If `true`, transparently follow HTTP redirects. Cannot be set to `false` on the client. Default `true`.
 * @param {Function} options.beforeSend On the client, this will be called before the request is sent to allow for more direct manipulation of the underlying XMLHttpRequest object, which will be passed as the first argument. If the callback returns `false`, the request will be not be sent.
 * @param {Function} [asyncCallback] Optional callback.  If passed, the method runs asynchronously, instead of synchronously, and calls asyncCallback.  On the client, this callback is required.
 */
HTTP.call = function(method, url, options, callback) {

  ////////// Process arguments //////////

  if (! callback && typeof options === "function") {
    // support (method, url, callback) argument list
    callback = options;
    options = null;
  }

  options = options || {};

  if (typeof callback !== "function")
    throw new Error(
      "Can't make a blocking HTTP call from the client; callback required.");

  method = (method || "").toUpperCase();

  var headers = {};

  var content = options.content;
  if (options.data) {
    content = JSON.stringify(options.data);
    headers['Content-Type'] = 'application/json';
  }

  var params_for_url, params_for_body;
  if (content || method === "GET" || method === "HEAD")
    params_for_url = options.params;
  else
    params_for_body = options.params;

View on GitHub (pinned to 5076d2f818)

Solutions

  1. Add a callback as the last argument: HTTP.call(method, url, options, (err, res) => {...}).
  2. If you used HTTP.get/HTTP.post on the client, supply the callback form.
  3. Move the call to the server (via Meteor.method) if you need a synchronous result.

Example fix

// before
HTTP.call('GET', url, options);

// after
HTTP.call('GET', url, options, (err, res) => {
  if (err) { /* handle */ }
  else { /* use res */ }
});
Defensive patterns

Strategy: validation

Validate before calling

function httpCallClient(method, url, options, callback) {
  if (typeof options === 'function') { callback = options; options = {}; }
  if (typeof callback !== 'function') {
    throw new TypeError('HTTP.call on the client requires a callback');
  }
  return HTTP.call(method, url, options, callback);
}

Type guard

function hasCallback(args) {
  const last = args[args.length - 1];
  return typeof last === 'function';
}

Prevention

When it happens

Trigger: Calling HTTP.call(method, url) or HTTP.call(method, url, options) on the client with no callback. Passing options as an object but forgetting the trailing function argument.

Common situations: Porting server-side HTTP.call code (which supports blocking) to the client unchanged; assuming HTTP.get/HTTP.post wrappers work without a callback on the client.

Related errors


AI-assisted analysis of meteor/meteor@5076d2f818 (2026-08-13). Data as JSON: /api/errors/d56894b587ee1629. Report an issue: GitHub.