{"record":{"id":"38e2651ad576c7fd","repo":"codex-team/editor.js","slug":"unable-to-move-block-up-since-it-is-already-the-fi","errorCode":null,"errorMessage":"Unable to move Block up since it is already the first","messagePattern":"Unable to move Block up since it is already the first","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/components/block-tunes/block-tune-move-up.ts","lineNumber":63,"sourceCode":"  public render(): TunesMenuConfig {\n    return {\n      icon: IconChevronUp,\n      title: this.api.i18n.t('Move up'),\n      onActivate: (): void => this.handleClick(),\n      name: 'move-up',\n    };\n  }\n\n  /**\n   * Move current block up\n   */\n  public handleClick(): void {\n    const currentBlockIndex = this.api.blocks.getCurrentBlockIndex();\n    const currentBlock = this.api.blocks.getBlockByIndex(currentBlockIndex);\n    const previousBlock = this.api.blocks.getBlockByIndex(currentBlockIndex - 1);\n\n    if (currentBlockIndex === 0 || !currentBlock || !previousBlock) {\n      throw new Error('Unable to move Block up since it is already the first');\n    }\n\n    const currentBlockElement = currentBlock.holder;\n    const previousBlockElement = previousBlock.holder;\n\n    /**\n     * Here is two cases:\n     *  - when previous block has negative offset and part of it is visible on window, then we scroll\n     *  by window's height and add offset which is mathematically difference between two blocks\n     *\n     *  - when previous block is visible and has offset from the window,\n     *      than we scroll window to the difference between this offsets.\n     */\n    const currentBlockCoords = currentBlockElement.getBoundingClientRect(),\n        previousBlockCoords = previousBlockElement.getBoundingClientRect();\n\n    let scrollUpOffset;\n","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/codex-team/editor.js/blob/5f45dabbe5690b7033b2f9047d3985add5045fdd/src/components/block-tunes/block-tune-move-up.ts#L45-L81","documentation":"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.","triggerScenarios":"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).","commonSituations":"User clicks Move Up on the first block; index desync after blocks were removed asynchronously while the tune menu was open.","solutions":["Guard before moving: only call move when currentIndex > 0","Hide/disable the Move Up tune for the first block","Re-fetch the current index immediately before acting instead of caching it"],"exampleFix":"// before\napi.blocks.move(api.blocks.getCurrentBlockIndex() - 1);\n// after\nconst idx = api.blocks.getCurrentBlockIndex();\nif (idx > 0) {\n  api.blocks.move(idx - 1);\n}","handlingStrategy":"validation","validationCode":"const idx = api.blocks.getCurrentBlockIndex(); if (idx > 0) { api.blocks.move(idx - 1); }","typeGuard":"const canMoveUp = (api: API): boolean => api.blocks.getCurrentBlockIndex() > 0;","tryCatchPattern":"try { tune.handleClick(); } catch (e) { if (e instanceof Error && e.message.includes('already the first')) return; throw e; }","preventionTips":["Re-read the index right before moving","Hide Move Up for the first block"],"tags":["block-tune","move-up","bounds-check","editorjs"],"backgroundTag":"index-out-of-bounds","analyzedSha":"5f45dabbe5690b7033b2f9047d3985add5045fdd","analyzedAt":"2026-08-27T22:50:23.124Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}