sveltejs/kit · error

query.live '${name}' must return an Iterator, Iterable, Asyn

Error message

query.live '${name}' must return an Iterator, Iterable, AsyncIterator or AsyncIterable

What it means

`query.live` returns a live stream of values, so the query function must return something iterable: a sync/async Iterator or Iterable (e.g. an async generator, array of promises, ReadableStream-like object). If the returned value supports none of `Symbol.asyncIterator`/`Symbol.iterator` protocols, `to_iterator` throws this error. Return an (async) generator or iterable from the `query.live` function.

Source

Thrown at packages/kit/src/runtime/app/server/remote/shared.js:216

 * @param {Awaited<RemoteLiveQueryUserFunctionReturnType<T>>} source
 * @param {string} name
 * @returns {Iterator<T> | AsyncIterator<T>}
 */
function to_iterator(source, name) {
	// intentionally using `in` because these could be inherited
	if ('next' in source && typeof source.next === 'function') {
		return source;
	}

	if (Symbol.asyncIterator in source && typeof source[Symbol.asyncIterator] === 'function') {
		return source[Symbol.asyncIterator]();
	}

	if (Symbol.iterator in source && typeof source[Symbol.iterator] === 'function') {
		return source[Symbol.iterator]();
	}

	throw new Error(
		`query.live '${name}' must return an Iterator, Iterable, AsyncIterator or AsyncIterable`
	);
}

/**
 * Note that `state` is deliberately not optional: resources that capture the request
 * state at creation must pass it explicitly, because reading it from the request store
 * at call time is only equivalent on runtimes with `AsyncLocalStorage` support.
 * Callers without a captured state (such as the module-level `form` instance getters)
 * should pass `get_request_store().state` themselves.
 * @param {RemoteInternals} internals
 * @param {RequestState} state
 */
export function get_cache(internals, state) {
	let cache = state.remote.data?.get(internals);

	if (cache === undefined) {
		cache = {};

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Make the query function an async generator: `query.live(async function* () { yield* stream; })`
  2. Return an async iterable source (e.g. an event emitter wrapped with an async generator, or an array)
  3. If only one value is needed, use plain `query` instead of `query.live`

Example fix

// before
export const ticks = query.live(() => Date.now());
// after
export const ticks = query.live(async function* () {
  while (true) {
    yield Date.now();
    await new Promise((r) => setTimeout(r, 1000));
  }
});
Defensive patterns

Strategy: validation

Validate before calling

function assertAsyncIterable(value) {
  if (value == null || !(Symbol.asyncIterator in Object(value)) && !(Symbol.iterator in Object(value))) {
    throw new TypeError('query.live function must return an (async) iterable');
  }
  return value;
}

Type guard

const isIterable = (v) => v != null && (typeof v[Symbol.asyncIterator] === 'function' || typeof v[Symbol.iterator] === 'function');

Try / catch

try {
  const iter = to_iterator(result);
} catch (e) {
  if (e.message.includes('must return an Iterator')) {
    console.error('Wrap the single value in an async generator before returning');
  }
  throw e;
}

Prevention

When it happens

Trigger: A `query.live` function whose return value is a plain object, a Promise of a non-iterable, `undefined`, a number/string-wrapped value without iterator protocol, or a plain single value instead of a stream.

Common situations: Returning the result of `db.query()` (a plain Promise resolving to one row) instead of a cursor/stream; forgetting `async function*` and using `async function`; returning an object map instead of an array.

Related errors


AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02). Data as JSON: /api/errors/0bad0ba3b9c2702f. Report an issue: GitHub.