Spot the bug - #139: Inventory Ledger

Why is my wizard shop displaying property names instead of values?

const potionInventory = {
  healingDraught: 15,
  manaElixir: 8,
  invisibilityBrew: 3,
  dragonTears: 1
};

function formatStockReport(stock) {
  const reportLines = [];
  const entries = Object.keys(stock);

  for (let i = 0; i < entries.length; i++) {
    const [item, count] = entries[i];
    const label = item.replace(/([A-Z])/g, ' $1').toLowerCase();
    reportLines.push(`${label.trim()}: ${count} bottles in stock`);
  }

  return reportLines.join('\n');
}

function calculateRestockCost(stock, costPerUnit = 5) {
  let totalBottles = 0;
  for (const item in stock) {
    if (Object.hasOwn(stock, item)) {
      totalBottles += stock[item];
    }
  }
  return totalBottles * costPerUnit;
}

console.log('--- Current Inventory ---');
console.log(formatStockReport(potionInventory));
console.log(`Estimated restock budget: $${calculateRestockCost(potionInventory)}`);

Reply with what is broken and how you would fix it.

The problem is that you’re using Object.keys(), which returns only property names.
Change:
const entries = Object.keys(stock);
to:
const entries = Object.entries(stock);
Then this works correctly:
const [item, count] = entries[i];
Object.entries() gives you both the property name and value, e.g. [“healingDraught”, 15].

lol nice catch @emmawalter5! we’ll see if that’s the one when the answer goes up later today.

I think the bug is in the updateItem function. It’s decrementing a quantity field without checking if it exists first.

Nah, it’s actually in the removeItem function. that one tries to delete an item based on an ID that might not exist in the ledger at all.

The removeItem function should check if the ID exists before trying to delete it. Otherwise, you’re just throwing an error for nothing.

Okay so the real bug is that removeItem just assumes the ID is there. that’s a classic race condition waiting to happen if you have multiple things hitting the ledger.

You’re right! Object.keys() only gives you the property names. You need Object.entries() to get both the key and the value.

Here’s a quick guide on how Object.entries() works if you want to dive deeper: https://www.kirupa.com/html5/getting_object_properties_values.htm

The Object.entries() approach is correct for iterating over both keys and values. The original problem likely stemmed from a misunderstanding of how Object.keys() behaves.

Spot the Bug answer: The destructuring assignment const [item, count] = entries[i]; is incorrectly trying to destructure a string into two variables.

The fix:

Change `const entries = Object.keys(stock);` to `const entries = Object.entries(stock);`.

Why:
Object.keys() returns an array of strings (the property names). When entries[i] is a string like ‘healingDraught’, destructuring [item, count] from it assigns ‘h’ to item and ‘e’ to count. To get both key and value, Object.entries() should be used, which returns an array of [key, value] pairs.


Got it: @emmawalter5 :trophy:

First-answer leaderboard

  1. @Apexcodes - 6 (firsts) :trophy:
  2. @kirupa - 6 (firsts) :trophy:
  3. @emmawalter5 - 4 (firsts)
  4. @adnanahmed - 2 (firsts)