Chrome fails to read message fron Native host if the message length is multiple of 256

I’m building a chrome extension what utilizes a native messaging host for getting information about the DOM and transfer them to another app. During my testing i managed to send a message to the chrome extension that was exactly 266 bytes long (270 accounting the 4 bytes for length). After some investigation, I found out that this message length is not the only one which is problematic. Every multiple of 256 (256, 512, 768, 1024, 1280, 1536, 1792, 2048,… and especially 2560), added 10, sometimes 20 and 30, caused the chrome to stop parsing from host’s stdout. The native host, continues to send data and ultimately, an exception “The sender sent an invalid JSON message; message ignored.” appears without context. After that, the chrome invalidates the stdin of the native host, bringing it to a close.

Extension Manifest

[...]
"manifest_version": 3,
    "permissions": [
        "storage",
        "tabs",
        "background",
        "notifications",
        "nativeMessaging",
        "scripting",
        "debugger"
    ],
    "host_permissions": [
        "https://*/*",
        "http://*/*"
    ],
    "background": {
        "service_worker": "scripts/background.js"
    },
    "content_scripts": [
        {
            "matches": [
                "http://*/*",
                "https://*/*"
            ],
            "js": [
                "scripts/content.js"
            ]
        }
    ],
[...]

Background script (Sample)

const nativeID = "com.nmhost";
var nmhostPort = chrome.runtime.connectNative(nativeID);

const onNativeMessage = function (msg) {
    // if (dbgFlag && dbgLvl == 3) {
    //     console.log("Received: n" + JSON.stringify(msg, null, 4));
    // }
    let ss = JSON.stringify(msg);
    console.log(`Received:[${ss.length}]`);
    return;
}

nmhostPort.onMessage.addListener(onNativeMessage);
nmhostPort.onDisconnect.addListener(function () {
    console.error("NMHost Disconnected");
});

Native host (C++) (Sample)

/**
 * @brief Get the Message from Chromium. If the length of the message is zero or less it does not read the message!
 *
 * @param buff The message buffer to return
 * @return int32_t
 */
int32_t GetExtMessage(char *buff) {
    // if stdin fails retry 3 times
    for (int i = 0; i < STDIN_RETRY; i++) {
        int32_t reqLen = 0;
        std::cin.read(reinterpret_cast<char *>(&reqLen), 4);
        if (reqLen > 0) {
            std::cin.read(buff, reqLen);
            return reqLen;
        } else {
            if (std::cin.fail()) {
                std::cerr << "STDIN FAILED!. RETRYING..." << std::endl;
                std::cin.clear();
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(), EOF);
                std::this_thread::sleep_for(std::chrono::milliseconds(FAIL_WAIT_MILIS));
            }
        }
    }
    return -1;
}

/**
 * @brief Sends a message to Chromium
 *
 * @param msg The message to send
 */
void SendExtMessage(std::string msg) {
    uint32_t responseLen = msg.length();
    char *bt_len = reinterpret_cast<char *>(&responseLen);
    std::cout.write(bt_len, 4);
    std::cout.write(msg.c_str(), responseLen);
    std::cout.flush();
}

int main(int argc, char *argv[]) {

    // set stdin mode to BINARY
    if (_setmode(_fileno(stdin), _O_BINARY) == -1) {
        Log("[Error]. Could not set output mode to binary");
        return 1;
    }
    //wait a bit
    std::this_thread::sleep_for(std::chrono::seconds(5));
    // send bytes to stdout
    for (int i = 1; i < 100000; i++) {
        // if (i == 256 || i == 510 || i == 512 || i == 768 || i == 1024 || i == 1280 || i == 1536 || i == 1792 || i == 2048 ) {
        //     continue;
        // }
        //keep in mind that final json value has 10 more bytes which are {"msg":""}
        nlohmann::json jj = {{"msg", ""}};
        for (int j = 0; j < i; j++) {
            jj["msg"] = std::string(jj["msg"]) + "a";
        }
        std::string s = jj.dump();
        // Log("Sending " + s + " bytes");
        SendExtMessage(s);
        jj["msg"] = "";
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    return 0;
}

A workaround i found is to add dummy bytes to the messaage is the len is of such numbers, but again it get stuck to len = 2560 and i really don’t like this.

void SendExtMessage(std::string msg) {
    uint32_t responseLen = msg.length();
    if ((responseLen - 10) % 256 == 0 || responseLen % 256 == 0 || (responseLen - 10 * (responseLen / 256)) % 256 == 0) {
        nlohmann::json j = nlohmann::json::parse(msg);
        j["xxx"] = 1;
        msg = j.dump();
        responseLen = msg.length();
    }
    char *bt_len = reinterpret_cast<char *>(&responseLen);
    std::cout.write(bt_len, 4);
    std::cout.write(msg.c_str(), responseLen);
    std::cout.flush();
    Log("[Log] Writing " + std::to_string(responseLen) + " bytes to stdout");
}

Image of the output & logs (left is the native host logs, right is the developer tools of chrome with the background script output)

Have anyone encountered anything like this?

document.getElementById returns null in Netsuite client script and in developers tool

I am attaching client script to Nestuite iframe suitelet to hide div element.

Here’s the strange part:
1.If I inspect the element in the browser’s developer tools and then execute document.getElementById('abc') in the console, it returns null.
2. But, if I copy the JSON path of the element in the developer tools and then execute document.getElementById('abc') in the console, it correctly returns the element.

Below in Netsuite client script:

//Client Script
function pageInit(scriptContext) {
    document.getElementById("uif37");
}

//i_frame suitelet
 if (context.request.method === 'GET') {

            var form = serverWidget.createForm({title: 'Monitoring System', hideNavBar: true});
           
            // Construct URLs for child Suitelets
            var fisrtiframeUrl = buildIframeUrl('scriptid', 'deployid');
            var secondiframeUrl = buildIframeUrl('scriptid', 'deployid);
          

            var fisrtiFrameHtml = "<iframe src='" + fisrtiframeUrl + "' id='view' width='50%' height='700px' scrolling='auto'  name='firstframeView' marginheight='0' marginwidth='0' frameborder='0'></iframe>";
            var secondiFrameHtml = "<iframe src='" + secondiframeUrl + "' id='view' width='50%' height='700px' scrolling='auto' name='secondframeView' marginheight='0' marginwidth='0' frameborder='0'></iframe>";
        

            var combinedHtml = fisrtiFrameHtml + secondiFrameHtml;

            var htmlField = form.addField({
                id: 'custpage_my_iframe',
                type: serverWidget.FieldType.INLINEHTML,
                label: 'Performance  iFrame'
            });
            htmlField.defaultValue = combinedHtml;
            form.clientScriptModulePath = 'SuiteScripts/cs_hide_div.js';


            form.addResetButton({label: 'Cancel'});

            context.response.writePage(form);
        }
    }

How to properly compare child.type in a React Server Component?

I’m building a UI library with React. We use the Children API and some child.type checks to filter specific children, like this for example:

const listItems = React.Children.map(children, (child) => {
  if (React.isValidElement(child) && child.type === ListItem) {
    return React.cloneElement(child);
  }
});

This works fine in Client Components, but users report that it breaks in React Server Components. The comparison child.type === ListItem fails, likely due to differences in module resolution between server and client.

I know that the Children API is somewhat legacy and switching to render props might be the better long-term solution, but that would require breaking changes across many components.

Question:

Is there a way to fix the child.type comparison so it works inside a React Server Component? Or is switching to a different pattern the only viable solution?

Any insights would be appreciated!

shadow dom isolation isn’t working as expected

I have a widget module which is made in react and react-bootstrap and to load this widget I have created an external function runOOB and I want to load this function in one of my websites with the help of shadow dom

async function runOOB(element_id, business_id, env=’prod’)
{

function loadScript(element_id, url, callback)
{
    // Adding the script tag to the head as suggested before
    var eObj = document.getElementById(element_id);
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    if(callback)
    {
        script.onreadystatechange = callback;
        script.onload = callback;
    }    
    // Fire the loading
    eObj.appendChild(script);
} 

// Get the container where the div will be appended
const container = document.getElementById(element_id);
//Create root div
var divRoot=document.createElement('div');
divRoot.id='div_root';
divRoot.name='div_root';


//const shadowRoot=divRoot.attachShadow({ mode: "open" });
//tmpRoot=divRoot.shadowRoot;

// Create a new div element
var div = document.createElement('div');

// Set the div attributes
div.id='oob_div';
div.name='oob_div';
div.width = '100%'; // Set the width of the div
div.style.fontSize='14px';

// Optionally, you can set other attributes like style, frameBorder, etc.
div.style.border = 'none';
div.style.textAlign = 'center';


var img = document.createElement('img');
img.id="loading_gif";
img.name="loading_gif";
img.src=widgetURL + "/loading.gif";
img.alt="loading_gif";
img.style.width="100px";

var lText=document.createElement('div');
lText.innerText="Loading ... ";
lText.style.padding="20px";
div.appendChild(img);
div.appendChild(lText);

// Append the div to the container
//shadowRoot.appendChild(div);
divRoot.appendChild(div);
container.appendChild(divRoot);
console.log('Start loader');
//container.style.overflow='hidden';

 // Add event listener for messages from the div
window.addEventListener('message', function(event) {
    // Adjust the height of the div based on the message received
    if (event.data.type === 'setHeight' && div) {
        console.log('Revising height to: ',event.data.height)
        div.style.height = event.data.height + 'px';
    }
});

function strapDiv()
{
    // Wait until the div is properly appended to the shadowRoot
    const interval = setInterval(() => {
        const oobDiv = document.getElementById('oob_div');
        if (oobDiv) {
            clearInterval(interval);
            console.log('Remove loader');
            document.getElementById('oob_div').style.textAlign="left";
            OOBWidget.loadReactApp(oobDiv, business_id);

        }
    }, 100);
}

loadScript('div_root',"https://unpkg.com/react@18/umd/react.production.min.js",null);
loadScript('div_root', "https://unpkg.com/react-dom@18/umd/react-dom.production.min.js",null);
loadScript('div_root', widgetURL + "/dist/oob_widget.js", strapDiv);      

}

const host = document.getElementById(‘shadow_root’);
const shadowRoot = host.attachShadow({ mode: ‘open’ });

                                        const style = document.createElement("link");
                                        style.rel = "stylesheet";
                                        style.href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css";
                                        shadowRoot.appendChild(style);

                                        const styleTag = document.createElement("style");
                                        styleTag.textContent = `
                                            * {
                                                all: iniial;
                                                font-family: inherit;
                                            }
                                            `;
                                        shadowRoot.appendChild(styleTag);
                                      
                                        const container = document.createElement('div');
                                        container.className = 'padding-top-100';
                                        shadowRoot.appendChild(container);
                            
                                        const widgetContainer = document.createElement('div');
                                        widgetContainer.id = 'my_root';
                                        widgetContainer.style.cssText = 'width:100%; height:100%; padding:0; border-width:0;';
                                        container.appendChild(widgetContainer);
                            
                                        
                            
                                        const externalScript = document.createElement('script');
                                        externalScript.src = 'https://widget-dev.orderonbot.com/loadOOB_demo.js';
                            
                                        externalScript.onload = function() {
                                            setTimeout(() => {
                                                if (typeof runOOB === 'function') {
                                                    runOOB(widgetContainer.id, 'B-0253QOL', 'dev');
                                                } else {
                                                    console.error('runOOB is not available.');
                                                }
                                            }, 500);
                                        };
                                        container.appendChild(externalScript)
                                      </script>

                            </div>
                            </div>           
                        </section>
                </section>
                    </div>
                </div>
            </div>

        </div>

I don’t understand where I am doing wrong, can someone help me?

I wanted to implement google oauth in my angular application

So, i have built an application where we can assign tasks and set deadline etc. Everything was perfectly working (including my login and register page). I wanted to implement Third party authentication in this app. I implemented everything correctly and i know there is a minor mistake in there somehow. As soon as i click sign in with google, it perfectly goes to the google sign in page and lets me select my account. But after that, it shows “all fields are required” in my server. Help me fix it please. I am attaching the code for your reference.

[This is my login endpoint][1]. [This is my login.html][2]

”’

import { Component, OnInit } from '@angular/core';
import { GlobalTextBoxComponent } from '../global-text-box/global-text-box.component';
import { GlobalButtonComponent } from '../global-button/global-button.component';
import { FloatLabelType } from '@angular/material/form-field';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { RouterModule } from '@angular/router';

@Component({
  selector: 'app-login-page',
  imports: [GlobalTextBoxComponent, GlobalButtonComponent, RouterModule],
  templateUrl: './login-page.component.html',
  styleUrl: './login-page.component.scss',
})
export class LoginPageComponent  {
  textBoxes = [
    {
      label: 'Email',
      placeholder: 'Enter your email',
      value: '',
      type: 'email',
      disabled: false,
      floatLabel: 'auto' as FloatLabelType,
    },
    {
      label: 'Password',
      placeholder: 'Enter your password',
      value: '',
      type: 'password',
      disabled: false,
      floatLabel: 'auto' as FloatLabelType,
    },
  ];

  constructor(
    private http: HttpClient,
    private router: Router,
  ) {}

  

  updateTextBox(event: { label: string; value: string }) {
    const textBox = this.textBoxes.find((tb) => tb.label === event.label);
    if (textBox) textBox.value = event.value;
  }

  

  loginUser() {
    const userData = {
      email: this.textBoxes.find((tb) => tb.label === 'Email')?.value || '',
      password:
        this.textBoxes.find((tb) => tb.label === 'Password')?.value || '',
    };

    if (!userData.email || !userData.password) {
      console.error('All fields are required!');
      return;
    } else {
      this.router.navigateByUrl('/a-sign');
    }

    this.http.post('http://localhost:3000/login', userData).subscribe(
      (response: any) => {
        localStorage.setItem('authToken', response.token);
        localStorage.setItem('profile_picture', response.user.profile_picture);
        console.log('hey hey heyyyyyyy::::', localStorage.getItem('authToken'));
        console.log('Login successful!', response);
      },
      (error) => console.error('Login failed', error)
    );
  }
}

”’ This is my login.component.ts file. If there is anything else needed, kindly let me know.
[1]: https://i.sstatic.net/3KmmpRYl.png
[2]: https://i.sstatic.net/DznOQs4E.png

.NET MVC application scrolls back to the caller button. How to prevent it

I have a section in my .cshtml and when a button is clicked on that page it scrolls to the ‘contact-form’ section of the page. And this is exactly I want that.

But the problem is in my MVC application it’s going back to the button section where the button was clicked. Initially I should not see any movement when the button is clicked but I check by putting the breakpoint.

function scrollToContactForm(event) {
    event.preventDefault();

    document.getElementById('contact-form').scrollIntoView({
        behavior: 'smooth'
    });
}

There I could see that it’s actually going to that section contact-form. But after coming out of this method it goes to the button section again. Why?

<section class="section-contact-form" id="contact-form">
  <div class="contact-form"> 
  </div>        
</section>

Button html

<button onclick="scrollToContactForm(event)" class="banner-btn">Click Me</button>

And one thing I can say is that in my script nothing was written for scrolling back to caller position. And it’s not scrolling back to the top, it’s scrolling to the exact same position where the button was clicked.

I tried the same code in a plain .html file it worked but when I copied and pasted the same in my .cshtml page it behaves like this.

How bind async function in event Handler

I try to read a XML-File in chunks with sax and insert data into Oracle database with node-oracledb, but I run into difficulties with async functions. Here is my simplified code:

const { pipeline } = require('stream/promises');
const oracledb = require('oracledb');

let connection;
let sql = [];
let parser;
let rowCount = 0;

async function main() {
   const opts = { autoCommit: true, bindDefs: { val: { type: oracledb.STRING, maxSize: 80 } } };
   sql.push({ table: 'tab_A', cmd: `INSERT INTO TAB_A (COL) VALUES (:val)`, binds: [], options: opts });
   sql.push({ table: 'tab_B', cmd: `INSERT INTO TAB_B (COL) VALUES (:val)`, binds: [], options: opts });

   try {
      connection = await oracledb.getConnection({ user: 'user', password: 'secret', connectString: 'DB01' });
      await parse("my-file.xml");
      console.log(`Inserted ${rowCount} rows`);
   } catch (err) {
      console.error(err.stack);
   } finally {
      console.log(`Close connection`);
      if (connection)
         await connection.close();
   }
   console.log(`File imported`);
}

function createParser(handler, options = {}) {
   const sax = require('sax');
   const stream = sax.createStream(true);
   stream.on("closetag", onClose.bind(null, handler, options));
   return stream;
}

function onClose(handler, options, name) {
   handler(name);
}

async function parse(file) {
   const fs = require('fs');
   parser = createParser(processTag)
   const reader = fs.createReadStream(file);
   await pipeline(reader, parser);
   console.log(`File parsed`);
}


async function processTag(tag) {
   if (tag == 'NE') {
      // read one chunk, insert into DB
      for (let item of sql) {
         try {
            const result = await connection.executeMany(item.cmd, item.binds, item.options);
            rowCount += result.rowsAffected;
         } catch (error) {
            console.error(error);
         }
      }
      sql.find(x => x.table == 'tab_A').binds = [];
      sql.find(x => x.table == 'tab_B').binds = [];
   } else if (tag == 'moi') {
      sql.find(x => x.table == 'tab_A').binds.push({ val: 'some stuff from XML file' });
      sql.find(x => x.table == 'tab_B').binds.push({ val: 'some other stuff from XML file' });
   }
}

main();

I did not manage it to fully reproduce my problem, however I don’t think it matters in this case.

Code above works more or less, however the program runs and finishes without printing any of the messages like “Inserted ${rowCount} rows”, “File imported”, “File parsed”, etc.

In my real application (see xml-twig if you like to see more details) the first chunk is inserted and then I get error

Parsing done
Inserted 0 rows
Close connection
File imported
Error: NJS-003: invalid or closed connection
    at throwErr (C:DevelopingSourceMCMSServeransiblefilesnode_modulesoracledbliberrors.js:742:10)
    at Object.assert (C:DevelopingSourceMCMSServeransiblefilesnode_modulesoracledbliberrors.js:592:5)
    at Connection.executeMany (C:DevelopingSourceMCMSServeransiblefilesnode_modulesoracledblibconnection.js:1045:12)
    at async Connection.executeMany (C:DevelopingSourceMCMSServeransiblefilesnode_modulesoracledblibutil.js:271:16)
    at async Object.neHandler [as function] (C:DevelopingSourceMCMSServeransiblefilesnodeHuawei_NBI.js:95:28) {
  code: 'NJS-003'
}

I would assume by running await parse("my-file.xml"); it should not close the connection before XML-File is fully parsed and inserted.

How to use Image manipultion to move images around the canvas?

Hello I want to be able to make “img3” to move around the canvas however I’m having trouble doing so.

Any tips? got an assignment due in 2hrs (12pm gmt)

Here is the code:

let img1, img2, img3; // Image variables

// This is for satella moving around the screen
let xPos, yPos;
let xSpeed, ySpeed;

/// --- PRELOAD ------------------------
/// Preload images before the sketch runs
function preload() { 
  img1 = loadImage('assets/subaru_sad.png');
  img2 = loadImage('assets/subaru_wink.png'); 
  img3 = loadImage('assets/queen_of_satella.png');
  pixelDensity(1);
}

/// --- SETUP -------------------------
/// Initializes the canvas and logs image dimensions
function setup() {  
  console.info('Image dimensions');
  console.info('----------------');
  console.log("img1: ", img1.width, img1.height);
  console.log("img2: ", img2.width, img2.height);
  console.log("img3: ", img3.width, img3.height);
  console.info('----------------');

  noLoop(); // Prevents automatic redrawing
  createCanvas(img1.width, img1.height); //1080 for both
  xPos = random(0, width - img3.width);
  yPos = random(0, height - img3.height);
  frameRate(10); //controls the speed of the image
  xPos = random(0, width - 100);
  yPos = random(0, height - 100);
  xSpeed = random(2, 5);
  ySpeed = random(2, 5);


  
}

/// --- DRAW --------------------
/// Handles drawing the images and effects
function draw() {
  background(20); // Set dark background
  
  blendMode(SCREEN); // Apply blend mode for effects
  
  // Apply tint and draw the first image
  tint(255, 180);
  image(img1, 0, 0, width, height);
  img3.resize(200, 200);
 
  
  // Change blend mode and draw second image
  blendMode(MULTIPLY);
  tint(200, 150, 255, 180);
  image(img2, 50, 50, width - 100, height - 100);
  
  // Apply glitch effect
  applyGlitch(img1);

  xPos += xSpeed;
  yPos += ySpeed;
  if (xPos <= 0 || xPos + 100 >= width) {
    xSpeed *= -1;
  }
  if (yPos <= 0 || yPos + 100 >= height) {
    ySpeed *= -1;
  }


  // Randomly position multiple instances of Satella
  for (let i = 0; i < 10; i++) {
    let x = random(0, width - img3.width);
    let y = random(0, height - img3.height);

    xPos += xSpeed;
  yPos += ySpeed;
  if (xPos <= 0 || xPos + 100 >= width) {
    xSpeed *= -1;
  }
  if (yPos <= 0 || yPos + 100 >= height) {
    ySpeed *= -1;
  }

    image(img3, x, y);
  }
  


  
  

 // Update img3 position randomly
 

}
console.log(xPos, yPos);





/// --- APPLY GLITCH ----------------
/// Adds a random pixel distortion effect
function applyGlitch(img) {
  img.loadPixels();
  for (let i = 0; i < img.pixels.length; i += 4) {
    img.pixels[i] += random(-50, 50); // Red channel
    img.pixels[i + 1] += random(-50, 50); // Green channel
    img.pixels[i + 2] += random(-50, 50); // Blue channel
  }
  img.updatePixels();
  image(img, 0, 0, width, height);
}

/// --- CONVOLUTION (EDGE DETECTION) ----------------
/// Applies an edge detection filter to an image
function convolution(img) {
  img.loadPixels();
  let w = img.width;
  let h = img.height;
  let newImg = createImage(w, h);
  newImg.loadPixels();

  // Edge detection kernel
  let kernel = [
    [-1, -1, -1],
    [-1, 8, -1],
    [-1, -1, -1]
  ]; 

  for (let x = 1; x < w - 1; x++) {
    for (let y = 1; y < h - 1; y++) {
      let sum = 0;
      for (let i = -1; i <= 1; i++) {
        for (let j = -1; j <= 1; j++) {
          let idx = ((y + j) * w + (x + i)) * 4;
          sum += img.pixels[idx] * kernel[j + 1][i + 1];
        }
      }
      let newIdx = (y * w + x) * 4;
      newImg.pixels[newIdx] = sum;
      newImg.pixels[newIdx + 1] = sum;
      newImg.pixels[newIdx + 2] = sum;
      newImg.pixels[newIdx + 3] = 255;
    }
  }

  newImg.updatePixels();
  image(newImg, 0, 0);
}

/// --- CHANNEL REPLACE ----------------
/// Placeholder function for replacing pixel channels
function replaceChannel() {
  // Functionality needs to be implemented
}
html, body {
  margin: 0;
  padding: 0;
}
canvas {
  display: block;
}
<!DOCTYPE html><html lang="en"><head>
  <title>Simple pixel access</title>
  <script src="libraries/p5.min.js"></script>
  <link rel="stylesheet" type="text/css" href="style.css">
  <meta charset="utf-8">
  <style type="text/css">
    html {
      font-size: 10px;
    }
    body {
      margin: 2% 15%;
      font-size: 1.6rem;
      font-family: Arial, Helvetica, sans-serif;
    }
    canvas {
      vertical-align: top;
      margin: 1rem 1rem;
      border: 2px double black;
    }
  </style>
</head>
<body>
  <div>
    <h1>Subaru's contrast</h1>
    <h2>by Jking, 2025</h2>
    <p>
      Demonstration and template for different styles of compositing, blending, cropping, and scaling of images. 
    </p>
  </div>
  <script src="sketch.js"></script>
</body></html>

I tried everything from making an xPosition and a yPosition and adding random numbers to said positions but it doesn’t seem to actually move the “img3”

Sending a screenshot via email

I’ve got a page set up that allows a user to create a chart using sliders.

I’ve managed to create a button that allows them to download a screenshot directly to their computer/device.

However I also need it that they can fill in their email address and send the screenshot that way.

I’ve tried using some plugins on wordpress for creating email forms and whilst these all send correctly, I can’t get the screenshot to the body.

Does anyone have any advice, please?

Uncaught NotFoundError: Failed to execute ‘removeChild’ on ‘Node’: The node to be removed is not a child of this node. at removeChild

I am trying to make a component that uploads an image by opening a custom modal and after selecting the image file it displays the image as follows:-

Desired Output

But after selecting the image the screen goes blank. The custom modal opens on top of the current screen:-
Modal for upload

Here is my typescript code

import React, { useState, useRef } from "react";

const ImgUpldChild = () => {
  const [image, setImage] = useState<string | null>("https://upload.wikimedia.org/wikipedia/commons/thumb/4/48/Outdoors-man-portrait_%28cropped%29.jpg/640px-Outdoors-man-portrait_%28cropped%29.jpg");
  const [isModalOpen, setIsModalOpen] = useState(false);

  const openModal = () => setIsModalOpen(true);
  const closeModal = () => setIsModalOpen(false);

  const removeImage = () => {
    setImage(null);
  };

  const fileInputRef = useRef<HTMLInputElement>(null);

  // Open file picker when div is clicked
  const handleDivClick = () => {
    if (fileInputRef.current) {
      fileInputRef.current.click();
    }
  };

  // Handle image selection
  const handleImageChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];

    if (!file) {
        console.warn("No file selected");
        return;
    }

    const reader = new FileReader();

    reader.onload = () => {
        try {
            console.log("FileReader triggered");
            console.log("FileReader result type:", typeof reader.result);
            console.log("FileReader result:", reader.result);

            if (typeof reader.result === "string") {
                setTimeout(() => setImage(reader.result as string), 1000);
            }
        } catch (error) {
            console.error("Error in reader.onload:", error);
        }
    };

    reader.readAsDataURL(file);
};


  return (
    <div>
      <div className="row">
        <div className="col-sm-4 mb-4">
          <div className="form-group">
            <label className="guardian-img-box col-11">
              Father’s Photo

              {image ? (
                <div className="img-dlt-div">
                  <img src={image} alt="" className="preview-image" />
                  <button onClick={removeImage} className="delete-button">
                    <i className="far fa-trash-alt"></i>
                  </button>
                </div>
              ) : (
                <div className="upload-icon" onClick={openModal}>
                  <i className="fa-solid fa-arrow-up-from-bracket"></i>
                </div>
              )}
            </label>
          </div>
        </div>
      </div>

      {/* Modal for uploading image */}
      {isModalOpen && (
        <div className="modal-overlay">
          <div className="upload-modal">
            <div className="upload-content">
              <div className="drag-drop-box col-4">
                <span className="plus-icon">+</span>
              </div>
              <p className="upload-img-txt">Drag and drop photo here</p>
              <div className="divider">Or</div>
              <div className="upload-button" onClick={handleDivClick}>
                <i className="fa-solid fa-arrow-up-from-bracket"></i>
                <input type="file" accept="image/png, image/jpeg" ref={fileInputRef} onChange={handleImageChange} style={{ display: "none" }} />
              </div>
              <p className="upload-img-txt">Upload file</p>
              <p className="file-info">PNG, JPG up to 2MB</p>
            </div>
            <button className="close-button" onClick={closeModal}>
              ✖
            </button>
          </div>
        </div>
      )}
    </div>
  );
};

export default ImgUpldChild;

the reader.result shows the output in console:-

FileReader triggered ImgUpldChild.tsx:37

FileReader result type: string ImgUpldChild.tsx:38

FileReader result: data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASABIAAD/4gxUSUNDX1BST0ZJTEUAAQEAAAxEVUNDTQJAAABtbnRyUkdCIFhZWiAH0wAEAAQAAAAAAABhY3NwTVNGVAAAAABDQU5PWjAwOQA….

but after that i get:-

Uncaught NotFoundError: Failed to execute ‘removeChild’ on ‘Node’: The node to be removed is not a child of this node. at removeChild at ImgUpldChild.tsx:41:1

the line 41 of the code is setTimeout(() => setImage(reader.result as string), 100);

I have added an image link in the initial value of image in the useState() replace that with null or delete the current image with delete icon. Also, fontawesome fonts are used in this so either replace them with some symbol or use the fontawesome cdn.

Can someone explain what am I doing wrong or why react is crashing?

Use finafield helper in next.js server component

I’m using TinaCMS in Next.js 15.

I’d like to use Tina’s contextual editing but I would also like to have Next.js to compile the components server side, at build time.

However, if I want to use the tinaField helper it seems I have to use a useTina hook which requires “use client”.

import { useTina, tinaField } from 'tinacms/dist/react'

const Page = (props) => {
  const { data } = useTina(props)
  return (
    <div>
      <h1 data-tina-field={tinaField(data, 'title')}>{data.title}</h1>
    </div>
  )
} 

Is there anyone who dealt with this issue and knows a solution?

How to check it and write parameter which vcan be null in 1 line of code?

On laravel/vue site I made editor in both edit and insert mode and I pass task and editMode parameters :

export default defineComponent({
    props: {
        task: {
            type: Object,
            required: false, // In Insert mode property is empty
        },
        editMode: {
            type: Number,
            required: true,
        },

        
    setup(props) {
        let task = ref(props.task)
        let editMode = ref(props.editMode === 1)

        const form = ref({
            id: editMode ? task.value.data.id : '',
            title: editMode ? task.value.data.title : '',
            ...
        })
     

The code above work ok, if editMode is true, but otherwise I got error :

Uncaught (in promise) TypeError: task.value is undefined     

I suppose that in ? : construction task.value.data.id is rendered (I hoped no) anyway, even in case editMode is false.
How can I check it and write it in 1 line of code?

"@inertiajs/vue3": "^2.0.0",
"vue": "^3.4.0"
"element-plus": "^2.9.5"

Playwright execute setup database with 2 devices

I have 2 devices, chromium and a tablet. I want to execute a setup db script before each device, because the execution of the test on the first device may alter the results of the second one.

So the order would be something like this:

Setup for device 1 > tests execution with device 1 > Setup for device 2 > tests execution with device 2

I’ve tried so many things but I don’t know how to make it, I have something like this in my playwright.config.ts, but when run the tablet tests doesn’t execute:

 projects: [
        //look for the global.setup.ts file, when all the dependents ended call the teardown (cleanup db)
        {
            name: 'setup chromium db',
            testMatch: /global.setup.ts/,
            // teardown: 'cleanup chromium db',
        },
        {
            name: 'setup tablet db',
            testMatch: /global.setup.ts/,
            dependencies: ["chromium"],
        },
        //look for the global.teardown.ts file and execute it to clean up the db
        {
            name: 'chromium',
            use: {...devices['Desktop Chrome']},
            dependencies: ["setup chromium db"],
        },
        {
            name: "tablet",
            use: {
                viewport: {
                    width: 700,
                    height: 1110
                },
                userAgent: 'Mozilla/5.0 (Linux; Android 10; CustomTablet) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36',
                deviceScaleFactor: 2,
                isMobile: true,
                hasTouch: true,
                browserName: 'chromium',
            },
            dependencies: ["setup tablet db"]
        }
    ],```