codex-team/editor.js · error · Error

Unable to move Block up since it is already the first

Error message

Unable to move Block up since it is already the first

What it means

The 'Move up' block tune throws when the current block is the first block (index 0) or when the current/previous block cannot be resolved, since there is nothing above to swap with.

Source

Thrown at src/components/block-tunes/block-tune-move-up.ts:63

  public render(): TunesMenuConfig {
    return {
      icon: IconChevronUp,
      title: this.api.i18n.t('Move up'),
      onActivate: (): void => this.handleClick(),
      name: 'move-up',
    };
  }

  /**
   * Move current block up
   */
  public handleClick(): void {
    const currentBlockIndex = this.api.blocks.getCurrentBlockIndex();
    const currentBlock = this.api.blocks.getBlockByIndex(currentBlockIndex);
    const previousBlock = this.api.blocks.getBlockByIndex(currentBlockIndex - 1);

    if (currentBlockIndex === 0 || !currentBlock || !previousBlock) {
      throw new Error('Unable to move Block up since it is already the first');
    }

    const currentBlockElement = currentBlock.holder;
    const previousBlockElement = previousBlock.holder;

    /**
     * Here is two cases:
     *  - when previous block has negative offset and part of it is visible on window, then we scroll
     *  by window's height and add offset which is mathematically difference between two blocks
     *
     *  - when previous block is visible and has offset from the window,
     *      than we scroll window to the difference between this offsets.
     */
    const currentBlockCoords = currentBlockElement.getBoundingClientRect(),
        previousBlockCoords = previousBlockElement.getBoundingClientRect();

    let scrollUpOffset;

View on GitHub (pinned to 5f45dabbe5)

Solutions

  1. Guard before moving: only call move when currentIndex > 0
  2. Hide/disable the Move Up tune for the first block
  3. Re-fetch the current index immediately before acting instead of caching it

Example fix

// before
api.blocks.move(api.blocks.getCurrentBlockIndex() - 1);
// after
const idx = api.blocks.getCurrentBlockIndex();
if (idx > 0) {
  api.blocks.move(idx - 1);
}
Defensive patterns

Strategy: validation

Validate before calling

const idx = api.blocks.getCurrentBlockIndex(); if (idx > 0) { api.blocks.move(idx - 1); }

Type guard

const canMoveUp = (api: API): boolean => api.blocks.getCurrentBlockIndex() > 0;

Try / catch

try { tune.handleClick(); } catch (e) { if (e instanceof Error && e.message.includes('already the first')) return; throw e; }

Prevention

When it happens

Trigger: Clicking the Move Up tune (or calling handleClick) while the first block is focused; getBlockByIndex returning undefined for the current or previous block (e.g. stale index after concurrent DOM mutation).

Common situations: User clicks Move Up on the first block; index desync after blocks were removed asynchronously while the tune menu was open.

Related errors


AI-assisted analysis of codex-team/editor.js@5f45dabbe5 (2026-08-27). Data as JSON: /api/errors/38e2651ad576c7fd. Report an issue: GitHub.