Troubleshooting
Common errors and their solutions when working with farseer-client.
Dimension connections not filtering correctly
When filtering Arquero tables loaded from Farseer dimension tables, connections to other tables are arrays, not single values.
// WRONG - connections are arrays, not strings
const electronics = table.filter(d => d?.['Category'] === 'Electronics');
// Returns empty or incorrect results
// CORRECT - use [0] to access the first element
const electronics = table.filter(d => d?.['Category'][0] === 'Electronics');
Why: Dimension table connections (foreign keys) are stored as arrays. Always access with [0]:
// Filtering
table.filter(d => d?.['Category'][0] === 'Electronics');
// Deriving
table.derive({
CategoryName: d => d?.['Category'][0] || 'Unknown',
SupplierName: d => d?.['Supplier'][0] || 'N/A'
});
// Grouping
table.groupby(d => d?.['Category'][0]).count();
Unsupported expression construct: ChainExpression
Error: Unsupported expression construct: ChainExpression
at visit (/node_modules/arquero/dist/arquero.node.js:2907:7)
Cause: Arquero's expression parser doesn't support optional chaining (?.), nullish coalescing (??), and some other modern JavaScript syntax.
// WRONG - optional chaining not supported
const filtered = table.filter((d: any) => d?.value !== null && d?.value !== 0);
Fix: Wrap the expression in aq.escape():
import * as aq from 'arquero';
// CORRECT - use aq.escape()
const filtered = table.filter(aq.escape((d: any) => d?.value !== null && d?.value !== 0));
// Also for derive
const transformed = table.derive({
Years: aq.escape((d: any) => d.Years?.substring(1)),
Months: aq.escape((d: any) => d.Months?.substring(1))
});
When to use aq.escape():
- Optional chaining:
d?.value - Nullish coalescing:
d.value ?? 0 - Complex logic that Arquero's parser rejects
When NOT to use aq.escape():
- Simple expressions:
d => d.value > 0 - After
.objects()(plain JavaScript arrays don't need it)
TAG_IDs are incorrect/outdated
Symptom: Import fails because hardcoded tag IDs no longer match.
Fix:
- Use named lookups instead of hardcoded IDs when possible:
// Preferred - use names
const revenue = await client.getVariable('Revenue');
// Avoid - hardcoded IDs can become stale
const revenue = TAG_IDS.VARIABLES.REVENUE; - If hardcoded IDs are needed, verify them in Farseer UI and update
tagIds.ts.
Import job commit fails
Common causes:
-
Rows not visible before commit —
commit()automatically flushes remaining rows, but if you're debugging (breakpoint or commented-out commit), callflushRows()explicitly to see all rows in the UI:await importJob.addRows(rows);
await importJob.flushRows(); // Makes all rows visible for inspection
// await importJob.commit(); // Commented out for debugging -
Invalid dimension members - Validate data before import:
const products = await client.getDimensionMembersForTable('Product');
const validNames = products.map(p => p.name);
const validRows = rows.filter(r => validNames.includes(r[0])); -
Missing dimension in columns - Ensure all required dimensions are specified in the import job columns.
Connection/Authentication errors
-
Check environment variables:
echo $TENANT_ID
echo $FARSEER_API_KEY
echo $FARSEER_URL -
Verify manual configuration:
const client = new FarseerClient('tenant-id', 'api-key', 'https://app.farseer.io'); -
Check API key permissions in the Farseer UI under Settings > API Keys.
Debugging Tips
Check existing dimension members
await client.initTagMap();
const products = await client.getDimensionMembersForTable('Product');
products.forEach(p => console.log(p.name));
Dry run model.load
const result = await client.model.load({
model: { tables: [...] },
options: {
dryRun: true // Preview changes without applying
}
});
Inspect response errors
main().catch(async (error: any) => {
if (error && typeof error.text === 'function') {
console.error(await error.text());
} else {
console.error(error);
}
process.exit(1);
});