wavetermdev/waveterm · error

source cannot be blank

Error message

source cannot be blank

What it means

The term-wsh backend handler for vdomcreatecontext requires every RPC request to carry a non-blank source identifier identifying which block/origin sent it. rh.getSource() returning blank means the caller did not attach a source, so the handler refuses to proceed rather than routing output to an unknown destination.

Source

Thrown at frontend/app/view/term/term-wsh.tsx:29

import { isBlank } from "@/util/util";
import debug from "debug";

const dlog = debug("wave:vdom");

export class TermWshClient extends WshClient {
    blockId: string;
    model: TermViewModel;

    constructor(blockId: string, model: TermViewModel) {
        super(makeFeBlockRouteId(blockId));
        this.blockId = blockId;
        this.model = model;
    }

    async handle_vdomcreatecontext(rh: RpcResponseHelper, data: VDomCreateContext) {
        const source = rh.getSource();
        if (isBlank(source)) {
            throw new Error("source cannot be blank");
        }
        console.log("vdom-create", source, data);
        const tabId = globalStore.get(atoms.staticTabId);
        if (data.target?.newblock) {
            const oref = await RpcApi.CreateBlockCommand(this, {
                tabid: tabId,
                blockdef: {
                    meta: {
                        view: "vdom",
                        "vdom:route": rh.getSource(),
                    },
                },
                magnified: data.target?.magnified,
                focused: true,
            });
            return oref;
        } else if (data.target?.toolbar?.toolbar) {
            const oldVDomBlockId = globalStore.get(this.model.vdomToolbarBlockId);

View on GitHub (pinned to a4447c1563)

Solutions

  1. Ensure the RPC is issued from a BlockController/attached context so rh.getSource() resolves to a valid block id.
  2. Check how the RpcResponseHelper is constructed and that its source field is populated.
  3. If calling programmatically, pass an explicit source/blockid in the request.
  4. Guard the caller: verify the source is non-blank before dispatching the RPC.

Example fix

// before
await RpcApi.VDomCreateContext(globalEnv, data); // no source context
// after
const source = getBlockSource();
if (isBlank(source)) throw new Error("vdomcreatecontext requires a source block");
await RpcApi.VDomCreateContext(makeHelper(source), data);
Defensive patterns

Strategy: try-catch

Validate before calling

const source = getRpcSource(); // however the client resolves its block source
if (isBlank(source)) {
  throw new Error("cannot call VDomCreateContext: no source block attached");
}
await RpcApi.VDomCreateContext(helper, data);

Type guard

function hasValidSource(rh: RpcResponseHelper): boolean {
  return !isBlank(rh.getSource());
}

Try / catch

try {
  await RpcApi.VDomCreateContext(this, data);
} catch (e) {
  if (String(e.message) === "source cannot be blank") {
    console.error("RPC dispatched without a source block; check block/controller context");
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Invoking the VDomCreateContext RPC from a context with no source block set — e.g. a client constructed without a blockId/route context, a test harness, or an RPC issued before block registration so getSource() returns ""/null.

Common situations: Calling CreateBlock/VDOM commands from shared/global code outside a block controller, refactors that changed how RpcResponseHelper is constructed, or wsh calls issued from a non-block context.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/ebeb8ca2890a1f6f. Report an issue: GitHub.