Troubleshooting
Critical Issues
This guide covers common issues encountered when working with Grapa and GrapaPy, along with their solutions and debugging techniques.
See Also: - Getting Started - Debugging - Comprehensive debugging system for troubleshooting - Migration Tips for Python Users - Python Integration Guide
Common Error Patterns
{"error":-1}
Responses
Problem: Operations return {"error":-1}
instead of expected results.
Common Causes: 1. Namespace Issues: Objects created in local namespace are lost between calls 2. Missing Global Variables: Objects not properly stored in global namespace 3. Type Conversion Issues: Binary data not converted to appropriate types
Solutions:
Namespace Issues
# ❌ Problem: Object lost between calls (when using parameters)
xy.eval('table = {}.table("ROW")', {'x': 5})
xy.eval('table.mkfield("name", "STR")') # Error: table not found
# ✅ Solution: Use global namespace for parameterized execution
xy.eval('$global.table = {}.table("ROW")', {'x': 5})
xy.eval('table.mkfield("name", "STR")') # Success
# ✅ Alternative: Direct execution (no parameters) - variables persist automatically
xy.eval('table = {}.table("ROW")')
xy.eval('table.mkfield("name", "STR")') # Success
Type Conversion Issues
# ❌ Problem: Binary data not converted
result = xy.eval('table.get("user1", "name")') # Binary data
# ✅ Solution: Convert to appropriate type
result = xy.eval('table.get("user1", "name").str()') # String
Object Not Found Errors
Problem: Variables or objects are not found when expected.
Common Causes: 1. Local Namespace Clearing: Variables created in one call are lost in the next 2. Missing Global Declaration: Objects not stored in global namespace 3. Incorrect Variable Names: Typos or incorrect variable references
Solutions:
# ✅ Always use $global for persistent objects
xy.eval('$global.fs = $file()')
xy.eval('$global.table = {}.table("ROW")')
# ✅ Use variable names directly after global declaration
xy.eval('fs.set("test.txt", "content")')
xy.eval('table.mkfield("name", "STR")')
Field Type Issues
Problem: Integer fields are created as string types instead of integer types.
Common Cause: Incorrect field creation syntax for integer fields.
Solutions:
# ❌ Problem: May create string fields
xy.eval('table.mkfield("age", "INT", "FIX", 4)')
# ✅ Solution: Use without explicit mode for integers
xy.eval('table.mkfield("age", "INT")')
Syntax Errors
Problem: Grapa code fails to parse or execute.
Common Causes:
1. Incorrect Echo Syntax: Using function calls instead of method calls
2. Wrong Loop Syntax: Using for
loops instead of while
loops
3. Missing Parentheses: String concatenation not properly wrapped
Solutions:
Echo Syntax
/* ❌ Incorrect */
echo("Hello World");
/* ✅ Correct */
"Hello World".echo();
Loop Syntax
/* ❌ Incorrect */
for i in 1..10 {
echo("Item " + i);
}
/* ✅ Correct */
i = 1;
while (i <= 10) {
("Item " + i.str()).echo();
i = i + 1;
}
String Concatenation
/* ❌ Incorrect */
"Name: " + name.str() + ", Age: " + age.str().echo();
/* ✅ Correct */
("Name: " + name.str() + ", Age: " + age.str()).echo();
Array and Object Access Issues
Problem: Confusion about when to use bracket notation vs .get()
method.
Solution: Understand the distinction between different object types:
Arrays and Lists
/* ✅ Arrays support bracket notation */
element = ["a", "b", "c"];
value = element[1]; /* Returns "b" */
/* Note: .get() method not supported for arrays - use bracket notation */
/* ✅ Lists support bracket notation and .getname() */
obj = {"a": 11, "b": 22, "c": 33};
value = obj["b"]; /* Returns 22 */
name = obj.getname(1); /* Returns "b" */
/* Note: .get() method not supported for lists - use bracket notation */
$file and $TABLE Objects
/* ✅ ALWAYS use .getfield() and .setfield() for $file and $TABLE objects */
files = fs.ls();
file_info = files.getfield(0);
table_data = table.getfield("user1", "name");
/* ❌ Avoid bracket notation for $file and $TABLE objects */
file_info = files[0]; /* May not work reliably */
Property Names with Hyphens
/* ⚠️ IMPORTANT: Hyphens in property names require quotes */
/* The hyphen (-) is interpreted as a subtraction operator */
/* ❌ Problem: Hyphen interpreted as subtraction */
config = {ab:3, "a-b":4, a-b:5}; /* a-b becomes 5 (math operation) */
config.a-b; /* This is interpreted as config.a - b (subtraction) */
/* ✅ Solution: Use quotes for hyphenated names */
config = {ab:3, "a-b":4};
config["a-b"]; /* 4 (correct) */
config."a-b"; /* 4 (also correct) */
/* ✅ Also works for function calls */
config = {ab:3, "a-b":op(){44;}};
config."a-b"(); /* 44 */
Debugging Techniques
Check Object Types
# Check what type an object is
xy.eval('$global.debug_obj = some_operation()')
obj_type = xy.eval('debug_obj.type()')
print(f"Object type: {obj_type}")
Verify Global Variables
# Test if global variable exists
xy.eval('$global.test_var = "test"')
result = xy.eval('test_var')
print(f"Global variable: {result}")
Step-by-Step Debugging
# Test each step individually
xy.eval('$global.fs = $file()')
print("File object created")
xy.eval('fs.set("test.txt", "Hello")')
print("File written")
content = xy.eval('fs.get("test.txt").str()')
print(f"File content: {content}")
Error Pattern Analysis
# Check for specific error patterns
result = xy.eval('some_operation()')
if result == {"error":-1}:
print("Operation failed with error -1")
elif result.type() == "$ERR":
print("Operation returned error type")
else:
print(f"Operation succeeded: {result}")
GrapaPy Integration Issues
Namespace Persistence
Problem: Objects don't persist between Python calls.
Solution: Always use $global
for objects that need to persist:
# ✅ Correct pattern
xy.eval('$global.table = {}.table("ROW")')
xy.eval('table.mkfield("name", "STR", "VAR")')
xy.eval('table.set("user1", "John", "name")')
Type Conversion
Problem: Binary data returned instead of Python types.
Solution: Use Grapa's conversion methods:
# ✅ Convert binary data to Python types
name = xy.eval('table.get("user1", "name").str()')
age = xy.eval('table.get("user1", "age").int()')
salary = xy.eval('table.get("user1", "salary").float()')
Helper Classes
Problem: Repetitive code for common operations.
Solution: Create helper classes:
class GrapaTableHelper:
def __init__(self, grapa_instance, table_name):
self.xy = grapa_instance
self.table_name = table_name
self.xy.eval(f'$global.{table_name} = {}.table("ROW")')
def mkfield(self, name, field_type, mode="VAR", size=None):
if size:
self.xy.eval(f'{self.table_name}.mkfield("{name}", "{field_type}", "{mode}", {size})')
else:
self.xy.eval(f'{self.table_name}.mkfield("{name}", "{field_type}")')
def set(self, key, value, field):
self.xy.eval(f'{self.table_name}.set("{key}", "{value}", "{field}")')
def get(self, key, field, convert_type="str"):
return self.xy.eval(f'{self.table_name}.get("{key}", "{field}").{convert_type}()')
Command Line Issues
File Execution
Problem: .grc
files don't execute properly.
Solution: Use correct command line options:
# ✅ Correct: Use -f for .grc files
.\grapa.exe -f "examples/basic_example.grc"
# ❌ Incorrect: -c may cause parsing issues
.\grapa.exe -c "examples/basic_example.grc"
Quiet Mode
Problem: Too much output from version headers.
Solution: Use -q
flag to suppress version output:
.\grapa.exe -f "examples/basic_example.grc" -q
Debug Output Stream Separation
Problem: Debug output mixed with normal program output.
Solution: Use stream redirection to separate outputs:
# Separate normal and debug output
.\grapa.exe -d -f "script.grc" > normal_output.txt 2> debug_output.txt
# Suppress debug output entirely
.\grapa.exe -d -f "script.grc" 2> $null
# Capture only debug output
.\grapa.exe -d -f "script.grc" > $null 2> debug_output.txt
Note: Grapa properly separates normal program output (stdout) from debug output (stderr), allowing for flexible stream redirection and logging.
Best Practices for Debugging
1. Test Incrementally
# Test each operation step by step
xy.eval('$global.test = "Hello"')
print("Step 1: Variable created")
result = xy.eval('test')
print(f"Step 2: Variable retrieved: {result}")
xy.eval('$global.fs = $file()')
print("Step 3: File object created")
2. Use Descriptive Variable Names
# ✅ Good: Clear variable names
xy.eval('$global.user_table = {}.table("ROW")')
xy.eval('$global.file_system = $file()')
# ❌ Bad: Unclear variable names
xy.eval('$global.t = {}.table("ROW")')
xy.eval('$global.f = $file()')
3. Parameter Side Effects
Problem: Function parameters are modified unexpectedly
# ✅ Fixed: Default values are now immutable
f = op(x=0) {
x += 1;
x;
};
f(); // Returns 1
f(); // Returns 1 (expected - default value is not modified)
# ❌ Problem: Original variables are modified
data = [1, 2, 3];
process = op(arr) {
arr[0] = 999;
arr;
};
process(data); // Returns [999, 2, 3]
data; // Now [999, 2, 3] (unexpected!)
Solution: Use the .copy()
method or copy functions when you need to avoid side effects
// ✅ Solution 1: Use .copy() method (recommended)
data = [1, 2, 3];
process(data.copy()); // Returns [999, 2, 3]
data; // Still [1, 2, 3] (expected!)
// ✅ Solution 2: Copy function to avoid side effects
copy = op(x) { x; };
data = [1, 2, 3];
process(copy(data)); // Returns [999, 2, 3]
data; // Still [1, 2, 3] (expected!)
Why This Happens: Grapa uses pass-by-reference for performance reasons, avoiding the need for a full garbage collection system.
4. Check Return Values
# Always check what operations return
result = xy.eval('some_operation()')
print(f"Operation returned: {result}")
print(f"Type: {type(result)}")
4. Use Error Handling
try:
result = xy.eval('some_operation()')
if result == {"error":-1}:
print("Operation failed")
else:
print("Operation succeeded")
except Exception as e:
print(f"Exception occurred: {e}")
Common Patterns and Solutions
Table Operations Pattern
# ✅ Complete table operation pattern
xy.eval('$global.table = {}.table("ROW")')
xy.eval('table.mkfield("name", "STR", "VAR")')
xy.eval('table.mkfield("age", "INT")')
xy.eval('table.mkfield("salary", "FLOAT", "FIX", 8)')
xy.eval('table.set("user1", "John Doe", "name")')
xy.eval('table.set("user1", 30, "age")')
xy.eval('table.set("user1", 75000.50, "salary")')
name = xy.eval('table.get("user1", "name").str()')
age = xy.eval('table.get("user1", "age").int()')
salary = xy.eval('table.get("user1", "salary").float()')
File Operations Pattern
# ✅ Complete file operation pattern
xy.eval('$global.fs = $file()')
xy.eval('fs.set("test.txt", "Hello World")')
content = xy.eval('fs.get("test.txt").str()')
xy.eval('fs.rm("test.txt")')
This troubleshooting guide covers the most common issues and their solutions. When encountering problems, start with the namespace and type conversion issues, as these are the most frequent causes of {"error":-1}
responses.
For Python Users: If you encounter issues with GrapaPy integration, see the Migration Tips for Python Users and GrapaPy Namespace Solution for solutions to common problems and best practices.