{"record":{"id":"f24070a4b3461a36","repo":"actualbudget/actual","slug":"invalid-field-name-must-be-a-string","errorCode":null,"errorMessage":"Invalid field name, must be a string","messagePattern":"Invalid field name, must be a string","errorType":"exception","errorClass":"CompileError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/aql/compiler.ts","lineNumber":144,"sourceCode":"        path: [...acc.path, fullName],\n      };\n    },\n    { context: state.implicitTableName, path: [] },\n  ).path;\n\n  paths.forEach(path => {\n    if (!state.paths.get(path)) {\n      state.paths.set(path, makePath(state, path));\n    }\n  });\n\n  const pathInfo = state.paths.get(paths[paths.length - 1]);\n  return pathInfo;\n}\n\nfunction transformField(state, name) {\n  if (typeof name !== 'string') {\n    throw new CompileError('Invalid field name, must be a string');\n  }\n\n  const { path, field: originalField } = popPath(name);\n\n  let field = originalField;\n  let pathInfo;\n  if (path === '') {\n    pathInfo = {\n      tableName: state.implicitTableName,\n      tableId: state.implicitTableId,\n    };\n  } else {\n    pathInfo = resolvePath(state, path);\n  }\n\n  const fieldDesc = getFieldDescription(\n    state.schema,\n    pathInfo.tableName,","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/aql/compiler.ts#L126-L162","documentation":"transformField (compiler.ts:142) validates that every field reference passed to the compiler is a string. Dotted path strings are the only supported way to name fields; non-string values (numbers, objects, arrays) cannot be parsed into a path/field pair, so a CompileError is thrown immediately.","triggerScenarios":"q('transactions').select(123), select({ amount: 42 }) with a non-string value where a field name is expected, filter keys/values built from unvalidated user input, or passing a symbol/object instead of a field name string.","commonSituations":"Programmatic query building where field names come from variables, JSON configs, or API input; TypeScript-less code losing the intended string; refactors passing a field descriptor object where only its .name should go.","solutions":["Ensure the value passed to select/filter expressions is a string field name; convert with String(name) only if you're certain it's a name.","If building queries dynamically, validate field names are strings before composing the query.","For expressions, wrap values with q(expr) helpers so literal values are typed as literals rather than treated as field names."],"exampleFix":"// before\nq('transactions').select(someVar) // someVar = 42\n// after\nq('transactions').select('amount')","handlingStrategy":"type-guard","validationCode":"function assertStringField(name) {\n  if (typeof name !== 'string') {\n    throw new TypeError(`Field name must be a string, got ${typeof name}`);\n  }\n}","typeGuard":"function isFieldName(v) {\n  return typeof v === 'string' && v.length > 0;\n}","tryCatchPattern":"try {\n  runQuery(q);\n} catch (e) {\n  if (e.message === 'Invalid field name, must be a string') {\n    throw new Error('Check that query fields are passed as strings');\n  } else throw e;\n}","preventionTips":["Type query-building functions with TypeScript string types","Sanitize user/config-driven field selections before building queries","Use expression helpers for values instead of passing raw values as fields"],"tags":["aql","query","types","compile-error"],"backgroundTag":"invalid-field-name-type","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}