Runtime error during table lookup

I am going bonkers over this error–that doesn’t give me what the unknown item is. I have exhausted by debug messages to see what’s what, all seems ok.
Here is the table lookup

	otherwise if target is a magical weapon:
		choose row with an Enchantment of (magic-type of target) in the Table of Excelsiors;
	[Save the row data for use elsehwere]	
	now is-revealed entry is true;
	now found-magic-type is Magic-type entry;
	now found-description is Desc entry;
	now found-revealed-state is is-revealed entry;
	say "AUDIT: [found-magic-type] [found-revealed-state] [found-description][line break]";

and here is the table

Table of Excelsiors
Enchantment		is-revealed		Desc
"Short Sword +1"	false			"+1 To Hit and +1 Damage (d6+1); retrieved on command"
"Long Sword +2"	false			"+2 To Hit and +2 Damage (d8+2); retrieved on command"

Here is the item declaration:

The clean sword is on the cracked wall.
The clean sword is a magical weapon.
The magic-type of clean sword is "short sword +1".
Description of clean sword is "A normal looking short sword, but it is exceedingly clean and bright--not a speck of dirt (or blood) on it.[run paragraph on]".
Printed name of clean sword is "clean short sword".
Understand "short sword" as clean sword.

and here is the CAST action that triggers to table look-up:

Carry out Casting it on:
	let target be second noun;
	now target is revealed;	[item-specific; does not update reference table]
	if the topic understood matches "Read_Magic":
		reveal magical item data for target;
		say "The inscription glows faintly, morphs, then dims. The letters become...[line break][italic type][found-magic-type][roman type].";
		now printed name of target is "[found-magic-type in title case]";

All fields are defined; it does compile.
Here is the output error:
What do you do? cast read_magic on “clean short sword”

What do you do? cast read_magic on clean short sword

AUDIT: spell = read_magic; target = clean short sword

AUDIT: magic-type of clean short sword = short sword +1Casting Read Magic on item…

clean short sword = short sword +1

*** Run-time problem P21: Attempt to look up a non-existent correspondence in the table ‘Table of Excelsiors’.

Glulxe fatal error: Memory access out of range (-6CF7FFF8)

I have several other quite similar table lookups that work fine.
Can anyone help me with this runtime error?

I had to add some code to get the story to compile, since it’s not a complete self-contained example. Therefore, I’m not sure whether it now matches your scenario exactly. I just threw in a few necessary lines to see the issue; I was not aiming for best practices.

One additional problem was that the line now found-magic-type is Magic-type entry looks for a Magic-type column, but there is no such column. In my modification, I assumed that the Enchantment column was the right one, so I changed that line to: now found-magic-type is Enchantment entry.

Anyway, I managed to get the error with the following code:

The Dungeon is a room.

A weapon is a kind of thing.
A weapon can be magical.
A weapon has a text called magic-type.

A thing can be revealed.

Table of Excelsiors
Enchantment		is-revealed		Desc
"Short Sword +1"	false			"+1 To Hit and +1 Damage (d6+1); retrieved on command"
"Long Sword +2"	false			"+2 To Hit and +2 Damage (d8+2); retrieved on command"

The cracked wall is a supporter in the dungeon.

The clean sword is on the cracked wall.
The clean sword is a magical weapon.
The magic-type of clean sword is "short sword +1".
Description of clean sword is "A normal looking short sword, but it is exceedingly clean and bright--not a speck of dirt (or blood) on it.[run paragraph on]".
Printed name of clean sword is "clean short sword".
Understand "short sword" as clean sword.

found-magic-type is a text that varies.
found-description is a text that varies.
found-revealed-state is a truth state that varies.

To reveal magical item data for (target - a thing):
	if target is a magical weapon:
		say "looking for row with enchantment of [magic-type of target]";
		choose row with an Enchantment of (magic-type of target) in the Table of Excelsiors;
	[Save the row data for use elsewhere]	
	now is-revealed entry is true;
	[now found-magic-type is Magic-type entry;]
	now found-magic-type is Enchantment entry;
	now found-description is Desc entry;
	now found-revealed-state is is-revealed entry;
	say "AUDIT: [found-magic-type] [found-revealed-state] [found-description][line break]";
	
Casting it on is an action applying to one topic and one thing.
Understand "Cast [text] on [something]" as casting it on.

Carry out Casting it on:
	let target be second noun;
	now target is revealed;	[item-specific; does not update reference table]
	if the topic understood matches "Read_Magic":
		reveal magical item data for target;
		say "The inscription glows faintly, morphs, then dims. The letters become...[line break][italic type][found-magic-type][roman type].";
		now printed name of target is "[found-magic-type in title case]";

The problem is that the magic-type of the short sword is “short sword +1”, but the table’s Enchantment entry is “Short Sword +1”, with capital letters at the beginning. The entry is not found because the matching is case-sensitive.

The error disappears when you either change the magic-type of the sword to “Short Sword +1” or the table entry to all lower case “short sword +1”.

(It’s just a coincidence that your testing/auditing output mentions the short sword and thus appears to have chosen the correct row. AFAICT, Inform took the first row as a default. If you switch the order of the short sword and the long sword in the table, so that the long sword comes first, then the info for the long sword will be printed (in the erroneous code version).)

Yes, thank you. I found that Inform’s text matching is case-insensitive in the parser, but case-sensitive in table lookup.

It’s usually better to use a new kind of value (known in other programming languages as an enumeration) than to store and look up text in a table. For one thing, kinds of value are case insensitive! They can also be used as parser tokens quite easily.

Yes, thank you. I have about 80 things so I prefer not to use an enumeration. I have several tables and have a loop search algorithm. The default table search/lookup was causing too much trouble when I was trying to parameterize it into a single phrase.

What does the number of things have to do with anything? There’s no issue with defining an enumeration with hundreds of values if that’s what you need.

In fact, enumerations are more important when you have more values, because it means typoing one of them will be a compiler error instead of being silently ignored!

I prefer to use a table to lookup many properties of things from a single lookup key. That many enumerated values would be hard to read or find something I’m looking for.

If you use an enumerated value for the lookup key, though, then you don’t have to worry about making a typo (like what happened here).

What do you mean? What’s hard to read or find, exactly?

I need a table to contain at least 88 items, with associated properties. I have a lookup key that returns requested properties or values as I need them.

Perhaps I don’t understand how you mean me to use enumerated values.

I mean, I don’t understand what you think is worse about using enumerated values.

You weren’t thinking you have to define all 88 values in a single sentence, were you? This works just fine.

An item is a kind of value.
A burger is an item.
A sword is an item.

Though, given that you’re using a table anyway, I’d probably suggest going this route:

An item is a kind of value. The items are defined by the Table of Items.

And then the only other difference from what you’re doing now is that you don’t quote the item lookup key.

Though, I think that method broke in Inform 10 (it worked in older versions).

Each of about a hundred (declared) items that have properties that I need during play. I can’t see doing that without tables. I have a lookup key that allows me to retrieve whatever I need at the moment. I don’t see how enums help in this case.

We’re suggesting you keep your tables, but use an enum lookup key instead of a string lookup key. That means if you accidentally try to look up swrod instead of sword, the error will show up at compile time, not at run time.

Oh, I see. That does make more sense. Now, I define the lookup key with he declaration of the magic item. How do I do that with enums?