Back to Blog

Fix JavaScript Runtime Errors Faster with Gemini 3.5

Tutorials and Guides6308
Fix JavaScript Runtime Errors Faster with Gemini 3.5

Introduction

JavaScript runtime errors are a routine part of frontend development. A missing object field, an undeclared variable, an unmatched bracket, or an incorrect recursive function can interrupt rendering and break user interactions.

Traditional debugging still relies on browser console logs, breakpoints, stack traces, and manual code inspection. These tools remain essential. However, locating the root cause can take time, especially when the error appears only in production or depends on incomplete API data.

Gemini 3.5 can support this process by analyzing source code together with console output. It can explain why an exception occurred, identify the relevant line, and propose a corrected implementation. The model is most useful when developers provide enough context and verify every suggested change through tests.

This article demonstrates an AI-assisted debugging workflow through four common JavaScript errors:

Each example includes the faulty code, the underlying cause, a corrected implementation, and prevention guidance.

Why JavaScript Debugging Becomes Difficult

Simple syntax problems are often easy to fix. The harder cases involve differences between development and production environments.

Inconsistent API response structures

Local mock data is usually complete. Real APIs are less predictable. A nested object may be missing, a field may be null, or the backend may return a different structure during partial failures.

A page can therefore work correctly during development and fail only for a small percentage of production requests.

Scope and declaration mistakes

JavaScript supports function scope, block scope, module scope, and closure-based state. A variable declared with let or const exists only inside its current block.

When a function contains several loops and callbacks, it is easy to use a variable outside the scope in which it was declared.

Structural syntax errors

A missing parenthesis or brace can stop an entire script from loading. The console usually reports the token where parsing finally failed, not always the exact location where the mistake began.

This becomes harder to inspect in long files with deeply nested conditions.

Recursive logic errors

Recursive functions require a clear termination condition. Without one, each call adds a new frame to the call stack until the JavaScript engine stops execution.

The resulting error is clear, but the missing business condition may still require careful analysis.

AI can shorten the investigation process, but it should complement browser tools rather than replace them.

Case 1: TypeError When Accessing an Undefined Property

Runtime error

text
Uncaught TypeError: Cannot read properties of undefined
(reading 'nickname')

Faulty code

html
<!DOCTYPE html>
<html lang="en">
<body>
  <div id="name-box"></div>

  <script>
    const res = {
      code: 200,
      data: {}
    };

    const userName = res.data.user.nickname;

    document.getElementById("name-box").innerText = userName;
  </script>
</body>
</html>

Why the error occurs

The data object exists, but it does not contain a user property.

As a result:

javascript
res.data.user

evaluates to:

javascript
undefined

JavaScript cannot read nickname from undefined, so it throws a TypeError.

This issue often appears when frontend code assumes that every successful API response has the same nested structure.

Safer implementation

html
<!DOCTYPE html>
<html lang="en">
<body>
  <div id="name-box"></div>

  <script>
    const res = {
      code: 200,
      data: {}
    };

    const userName =
      res.data?.user?.nickname ?? "No nickname available";

    const nameBox = document.getElementById("name-box");

    if (nameBox) {
      nameBox.innerText = userName;
    }
  </script>
</body>
</html>

Optional chaining stops property access when an intermediate value is null or undefined.

javascript
res.data?.user?.nickname

Nullish coalescing then provides a fallback value:

javascript
?? "No nickname available"

Unlike the logical OR operator, ?? only replaces null and undefined. It does not replace valid values such as an empty string or 0.

Production recommendation

Optional chaining prevents the immediate crash, but it should not replace response validation.

For important API calls, validate the payload before rendering:

javascript
function getUserName(response) {
  if (
    response?.code !== 200 ||
    typeof response?.data?.user?.nickname !== "string"
  ) {
    return "No nickname available";
  }

  return response.data.user.nickname;
}

For larger projects, schema validation tools can detect malformed responses before the data reaches UI components.

Case 2: ReferenceError Caused by an Undeclared Variable

Runtime error

text
Uncaught ReferenceError: totalPrice is not defined

Faulty code

javascript
function countGoods(list) {
  list.forEach((item) => {
    const singlePrice = item.price;
    totalPrice += singlePrice;
  });

  return totalPrice;
}

const goodsList = [
  { price: 29 },
  { price: 59 },
  { price: 99 }
];

console.log(countGoods(goodsList));

Why the error occurs

The function uses totalPrice, but the variable is never declared.

When JavaScript executes this line:

javascript
totalPrice += singlePrice;

it attempts to resolve totalPrice in the current scope and its parent scopes. No matching declaration exists, so the runtime throws a ReferenceError.

This example is related to variable scope, but the direct cause is the missing declaration.

Corrected implementation

javascript
function countGoods(list) {
  let totalPrice = 0;

  list.forEach((item) => {
    const singlePrice = item.price;
    totalPrice += singlePrice;
  });

  return totalPrice;
}

const goodsList = [
  { price: 29 },
  { price: 59 },
  { price: 99 }
];

console.log(countGoods(goodsList));

The accumulator is now initialized before iteration:

javascript
let totalPrice = 0;

It remains available throughout the function.

Alternative implementation with reduce

For numeric accumulation, reduce can make the intention clearer:

javascript
function countGoods(list) {
  return list.reduce((total, item) => {
    const price = Number(item.price);

    return Number.isFinite(price)
      ? total + price
      : total;
  }, 0);
}

This version also protects the calculation from invalid values such as undefined, null, or non-numeric strings.

Coding recommendation

Declare shared state close to the beginning of the function. Use const by default and switch to let only when reassignment is required.

Static analysis can catch undeclared variables before runtime. ESLint’s no-undef rule is particularly useful:

json
{
  "rules": {
    "no-undef": "error"
  }
}

Case 3: SyntaxError from an Unmatched Parenthesis

Runtime error

text
Uncaught SyntaxError: Unexpected token '{'

Faulty code

javascript
const num = 15;

if (num > 10 {
  console.log("Number is greater than 10");
} else {
  console.log("Number is less than or equal to 10");
}

Why the error occurs

The condition starts with an opening parenthesis:

javascript
if (

but the closing parenthesis is missing.

The JavaScript parser expects the condition to end before the opening brace. When it encounters {, the token is invalid in that position.

That is why the console reports:

text
Unexpected token '{'

The brace is not the real problem. The missing ) before it is.

Corrected implementation

javascript
const num = 15;

if (num > 10) {
  console.log("Number is greater than 10");
} else {
  console.log("Number is less than or equal to 10");
}

Why these errors are easy to misread

Syntax errors are detected before the script begins execution. This means no later code runs, even if the rest of the file is valid.

The reported line often shows where the parser became unable to continue. The original mistake may appear several characters or lines earlier.

When diagnosing a syntax error, inspect:

Prevention practices

Modern development tools can catch this error before the browser does.

Useful protections include:

A practical script configuration might be:

json
{
  "scripts": {
    "lint": "eslint src --ext .js,.jsx",
    "format:check": "prettier --check src"
  }
}

AI is useful for explaining the parsing failure, but formatting and linting tools should remain the first automated defense.

Case 4: RangeError from Infinite Recursion

Runtime error

text
Uncaught RangeError: Maximum call stack size exceeded

Faulty code

javascript
function loopPrint(num) {
  console.log(num);
  loopPrint(num + 1);
}

loopPrint(1);

Why the error occurs

Each function call creates a new frame on the call stack.

The function calls itself here:

javascript
loopPrint(num + 1);

However, it contains no condition that stops the recursion.

The call sequence becomes:

text
loopPrint(1)
loopPrint(2)
loopPrint(3)
loopPrint(4)
...

Eventually, the JavaScript engine reaches its call-stack limit and throws a RangeError.

The exact stack limit depends on the browser, runtime, and execution environment.

Corrected recursive implementation

javascript
function loopPrint(num, max = 100) {
  if (num > max) {
    return;
  }

  console.log(num);
  loopPrint(num + 1, max);
}

loopPrint(1);

The function now contains a base case:

javascript
if (num > max) {
  return;
}

Once the condition is true, recursion stops.

Iterative alternative

Recursion is unnecessary for this task. A loop is clearer and avoids stack growth:

javascript
function loopPrint(start, max = 100) {
  for (let num = start; num <= max; num += 1) {
    console.log(num);
  }
}

loopPrint(1);

When recursion is appropriate

Recursion remains useful for hierarchical data, tree traversal, nested structures, and divide-and-conquer algorithms.

Every recursive function should answer three questions:

  1. What is the base case?
  2. Does each call move closer to that base case?
  3. Can the expected recursion depth exceed the runtime stack limit?

If the second answer is unclear, the function may enter an infinite recursive path.

A Reliable Gemini 3.5 Debugging Workflow

The quality of AI-assisted debugging depends heavily on the information provided to the model.

Sending only an error message often produces generic advice. A better request includes the runtime context, relevant source code, expected behavior, and known constraints.

Step 1: Preserve the original error

Copy the full console message and stack trace without rewriting it.

Useful details include:

Step 2: Provide the smallest complete example

Avoid sending one isolated line if the issue depends on data flow or variable scope.

Include:

The goal is not to provide the entire repository. It is to provide enough context to reproduce the failure.

Step 3: State the expected behavior

Do not only ask:

text
Fix this error.

A better request is:

text
This code runs in Chrome and displays a user's nickname
from an API response. The user object may be missing.

Explain the root cause of the TypeError and provide the
smallest safe correction. Preserve the existing DOM structure.
Do not introduce external dependencies.

This reduces unnecessary rewrites.

Step 4: Add engineering constraints

Tell the model what must remain unchanged.

Examples include:

Without these constraints, an AI may solve the error by changing unrelated behavior.

Step 5: Fix errors in execution order

When several console errors appear, start with the first uncaught exception.

Later errors may be side effects of the first failure. Fixing all messages simultaneously can lead to unnecessary changes.

After each correction:

  1. Reload the page or restart the process.
  2. Reproduce the original action.
  3. Check the console again.
  4. Run the relevant tests.
  5. Review the code diff.

Step 6: Request an explanation and prevention rule

A good debugging response should contain more than corrected code.

Ask the model to provide:

This turns one debugging session into reusable engineering knowledge.

Step 7: Verify the proposed change

AI-generated code must be treated as a candidate patch, not an automatically trusted solution.

Verify it through:

A change that removes an exception can still introduce incorrect business behavior.

Reusable Prompt Template

Developers can use the following structure:

text
You are debugging a JavaScript application.

Runtime environment:
- Browser: Chrome
- JavaScript: ES2020
- Framework: Vanilla JavaScript

Expected behavior:
[Describe the intended result]

Actual behavior:
[Describe what happens]

Console error:
[Paste the complete error and stack trace]

Relevant code:
[Paste the smallest complete example]

Constraints:
- Preserve the existing function signature
- Do not add external dependencies
- Keep compatibility with the specified environment
- Change only the code required to fix the issue

Please provide:
1. Root-cause analysis
2. The corrected code
3. An explanation of each change
4. One regression test
5. A prevention recommendation

This format helps the model distinguish technical symptoms from business requirements.

Conclusion

Gemini 3.5 can make JavaScript debugging faster, especially when a developer needs help interpreting stack traces, following data flow, or understanding unfamiliar language behavior.

The four cases in this article illustrate common failure patterns:

The most effective workflow combines AI analysis with established frontend tools. Browser DevTools, breakpoints, ESLint, formatters, type systems, and automated tests remain essential.

Developers should provide complete context, preserve original error messages, state business constraints, and verify every suggested patch. Used this way, AI becomes a debugging assistant rather than an uncontrolled code-rewriting system.

For teams that call several model providers from the same development platform, an aggregation service such as 4sapi can centralize endpoint access and usage records. Application-level validation, security controls, and testing should still remain within the engineering system.

Tags:Gemini 3.5JavaScriptFrontend DebuggingRuntime ErrorsTypeError

Recommended reading

Explore more frontier insights and industry know-how.