{"record":{"id":"c55c62534cbed850","repo":"actualbudget/actual","slug":"literal-not-passed-to-literal","errorCode":null,"errorMessage":"Literal not passed to $literal","messagePattern":"Literal not passed to \\$literal","errorType":"exception","errorClass":"CompileError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/aql/compiler.ts","lineNumber":638,"sourceCode":"      validateArgLength(args, 1);\n      return castInput(state, args[0], 'date-year');\n    }\n\n    // various functions\n    case '$condition':\n      validateArgLength(args, 1);\n      const conds = compileConditions(state, args[0]);\n      return typed(conds.join(' AND '), 'boolean');\n\n    case '$nocase':\n      validateArgLength(args, 1);\n      const [arg1] = valArray(state, args, ['string']);\n      return typed(`${arg1} COLLATE NOCASE`, args[0].type);\n\n    case '$literal': {\n      validateArgLength(args, 1);\n      if (!args[0].literal) {\n        throw new CompileError('Literal not passed to $literal');\n      }\n      return args[0];\n    }\n    default:\n      throw new CompileError(`Unknown function: ${name}`);\n  }\n});\n\nconst compileOp = saveStack('op', (state, fieldRef, opData) => {\n  const { $transform, ...opExpr } = opData;\n  const [op] = Object.keys(opExpr);\n\n  const rhs = compileExpr(state, opData[op]);\n\n  let lhs;\n  if ($transform) {\n    lhs = compileFunction(\n      { ...state, implicitField: fieldRef },","sourceCodeStart":620,"sourceCodeEnd":656,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/aql/compiler.ts#L620-L656","documentation":"The `$literal` function in the AQL compiler requires its argument to have been produced as a literal via `$literal` wrapping when the value was bound, so the compiler can inline it without escaping/inference. If the first argument's compiled state lacks `literal: true`, the compiler throws because `$literal` cannot safely emit the value.","triggerScenarios":"Using `{$literal: someExpr}` where `someExpr` resolves to a normal expression/parameter rather than a value marked with `literal` (e.g. produced from raw JS input compiled as a literal).","commonSituations":"Trying to inline raw values or fragments into a query without using the proper literal-binding API, or passing a field reference (`$field`) into `$literal` expecting it to be treated as raw.","solutions":["Pass an actual literal value (a plain string/number) to `$literal`, not a `$`-prefixed field reference.","Mark the value as a literal at binding time using the library's literal input mechanism (e.g. `lit()`/raw input helpers) so the compiled arg carries `literal: true`.","If you intended a parameterized value, use the normal `$param`/params mechanism instead of `$literal`."],"exampleFix":"// before\n{$literal: '$amount'}\n// after\n{$literal: 'transactions.amount'}","handlingStrategy":"validation","validationCode":"function assertLiteralArg(v) {\n  if (typeof v !== 'string' && typeof v !== 'number') {\n    throw new Error('$literal requires a raw string/number, not a $-expression');\n  }\n}","typeGuard":"const isRawLiteral = (v) => ['string', 'number', 'boolean'].includes(typeof v);","tryCatchPattern":null,"preventionTips":["Only pass raw JS values to $literal, never $-prefixed field refs.","Use parameter binding ($param) for dynamic values instead of $literal.","Document $literal as an escape hatch for raw SQL fragments."],"tags":["aql","query-compiler","literal"],"backgroundTag":"aql-invalid-literal","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}