#7445·decap-cms

NotFoundError: Node.removeChild: The node to be removed is not a child of this node

Author: cburwellCreated Mar 29, 2025Updated Sep 1, 2026

Describe the bug Error message appears at top of index.html where decap-cms.js is included via script tag from unpkg.com using manual CMS initialization.

To Reproduce

  • Include decap-cms.js
  • Manually initialize
  • Register two events to "preSave" hook
  • Call init()
  • Initialize local decap server with npx decap-server
  • Navigate to {localhost:port}/admin/index.html

Expected behavior No error expected.

Screenshots https://imgur.com/a/MjVc63H

Applicable Versions:

  • Decap CMS version: [email protected]
  • Git provider: proxy
  • Browser version: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0

CMS configuration

local_backend: true
backend:
  name: proxy
  branch: master
  commit_messages:
    create: Create {{collection}} “{{slug}}”
    update: Update {{collection}} “{{slug}}”
    delete: Delete {{collection}} “{{slug}}”
    uploadMedia: Upload “{{path}}”
    deleteMedia: Delete “{{path}}”
    openAuthoring: "{{message}}"
  proxy_url: http://localhost:8081/api/v1
media_folder: public/uploads
public_folder: /uploads
collections:
  - name: posts
    label: Posts
    folder: public/content/posts
    create: true
    slug: "{{year}}-{{month}}-{{day}}-{{slug}}"
    fields:
      - name: layout
        label: Layout
        widget: hidden
        default: posts
      - name: url
        label: URL
        widget: hidden
        default: "{{slug}}"
      - name: title
        label: Title
        widget: string
      - name: date
        label: Publish Date
        widget: datetime
        date_format: MM-DD-YYYY
        default: "{{now}}"
      - name: author
        label: Author
        widget: string
        default: ""
        required: false
      - name: description
        label: Description
        widget: string
        default: ""
        required: false
      - name: thumbnail
        label: Featured Image
        widget: image
        required: false
      - name: body
        label: Body
        widget: markdown
    publish: true
    type: folder_based_collection
    sortable_fields:
      - title
      - date
      - author
      - description
    view_filters: []
    view_groups: []
publish_mode: simple
slug:
  encoding: unicode
  clean_accents: false
  sanitize_replacement: "-"
isFetching: false
error: null

Additional context index.html content:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <meta name="robots" content="noindex"/>
    <script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
    <title>Content Manager</title>
</head>
<body>

<script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>

<script>
    window.CMS_MANUAL_INIT = true
    const {CMS, initCMS: init} = window

    CMS.registerEventListener({
        name: 'preSave',
        handler: ({author, entry}) => {
            if (!Object.getOwnPropertyDescriptor(entry.get('data'), 'author') ||
                entry.get('data').get('author').length === 0) {
                let newAuth = "";

                if (author && author.name) {
                    newAuth = author.name;
                }
                else if (localStorage.getItem('netlify-cms-user')) {
                    newAuth = JSON.parse(localStorage.getItem('netlify-cms-user'))?.name;
                }
                else if (author && author.login) {
                    newAuth = author.login;
                }

                if (newAuth.length === 0) {
                    newAuth = "Unknown Author";
                }

                return entry.get('data').set('author', newAuth);
            }
        },
    });

    CMS.registerEventListener({
        name: 'preSave',
        handler: ({entry}) => {
            if (!Object.getOwnPropertyDescriptor(entry.get('data'), 'description') ||
                entry.get('data').get('description').length === 0) {
                const _body = entry.get('data').get('body');
                let _desc = _body.length > 250 ? _body.substring(0, 247).trim() + "..." : _body;
                return entry.get('data').set('description', _desc);
            }
        },
    });

    init();
</script>
</body>
</html>