{"record":{"id":"c7acfb61ab066423","repo":"can1357/oh-my-pi","slug":"invalid-query-missing-in-query","errorCode":null,"errorMessage":"Invalid query: missing ] in ${query}","messagePattern":"Invalid query: missing \\] in (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/internal-urls/json-query.ts","lineNumber":35,"sourceCode":"\tif (!input) return [];\n\tif (input.startsWith(\".\")) input = input.slice(1);\n\tif (!input) return [];\n\n\tconst tokens: Array<string | number> = [];\n\tlet i = 0;\n\n\tconst isIdentChar = (ch: string) => /[A-Za-z0-9_-]/.test(ch);\n\n\twhile (i < input.length) {\n\t\tconst ch = input[i];\n\t\tif (ch === \".\") {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"[\") {\n\t\t\tconst closeIndex = input.indexOf(\"]\", i + 1);\n\t\t\tif (closeIndex === -1) {\n\t\t\t\tthrow new Error(`Invalid query: missing ] in ${query}`);\n\t\t\t}\n\t\t\tconst raw = input.slice(i + 1, closeIndex).trim();\n\t\t\tif (!raw) {\n\t\t\t\tthrow new Error(`Invalid query: empty [] in ${query}`);\n\t\t\t}\n\t\t\tconst quote = raw[0];\n\t\t\tif ((quote === '\"' || quote === \"'\") && raw.endsWith(quote)) {\n\t\t\t\tlet inner = raw.slice(1, -1);\n\t\t\t\tinner = inner.replace(/\\\\([\"'\\\\])/g, \"$1\");\n\t\t\t\ttokens.push(inner);\n\t\t\t} else if (/^\\d+$/.test(raw)) {\n\t\t\t\ttokens.push(Number(raw));\n\t\t\t} else {\n\t\t\t\ttokens.push(raw);\n\t\t\t}\n\t\t\ti = closeIndex + 1;\n\t\t\tcontinue;\n\t\t}","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/internal-urls/json-query.ts#L17-L53","documentation":"parseQuery tokenizes a jq-like query string (.foo.bar[0]) used to extract values from JSON payloads referenced by agent:// URLs. When it sees an opening '[' it searches for the matching ']' and throws if none exists anywhere later in the string. This guards the tokenizer against truncated or malformed bracket segments.","triggerScenarios":"Calling parseQuery or applyQuery with a string like '.foo[0' or '.items[\"key' where a '[' is never closed. Because the parser scans forward for the first ']', any '[' without a subsequent ']' triggers it, even if a later unrelated ']' would look balanced.","commonSituations":"Hand-written query strings in tool configs or model-emitted JSON extraction paths; truncated queries from URL parsing where brackets were stripped or percent-decoding mangled them; typos like '.foo[0].' missing the closing bracket.","solutions":["Add the missing closing ']' to the bracket segment in the query string.","If the key itself contains ']' (e.g. [\"a]b\"]), note this parser does not support it — restructure the data or use pathToQuery-safe keys.","Validate query strings with a regex like /^\\.?[A-Za-z0-9_-]+(\\[[^\\]]*\\]|\\.[A-Za-z0-9_-]+)*$/ before passing them to applyQuery."],"exampleFix":"// before\napplyQuery(data, \".foo[0\");\n// after\napplyQuery(data, \".foo[0]\");","handlingStrategy":"validation","validationCode":"function hasBalancedBrackets(q) { let d = 0; for (const c of q) { if (c === '[') d++; else if (c === ']') d--; if (d < 0) return false; } return d === 0; }\nif (!hasBalancedBrackets(query)) throw new Error(`Unclosed [ in query: ${query}`);","typeGuard":null,"tryCatchPattern":"try { tokens = parseQuery(query); } catch (e) { if (String(e.message).includes('Invalid query')) { /* surface query to user / fall back to raw path */ } else throw e; }","preventionTips":["Always write bracket segments as complete pairs: [0], ['key'].","Build queries with pathToQuery() instead of string concatenation.","Add a unit test per dynamic query template used in your config."],"tags":["parser","query-syntax","validation"],"backgroundTag":"query-syntax-error","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}