{"record":{"id":"682821a1cef6145c","repo":"temporalio/temporal","slug":"error-reading-contents-unmatched-end-if-keyword","errorCode":null,"errorMessage":"error reading contents: unmatched `END IF` keyword","messagePattern":"error reading contents: unmatched `END IF` keyword","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/persistence/query_util.go","lineNumber":134,"sourceCode":"\t\t\t\t\tif !hasWordAt(contentStr, sqlLoopKeyword, j) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tst = append(st, sqlLoopKeyword[0])\n\t\t\t\t\tj += len(sqlLoopKeyword) - 1\n\n\t\t\t\tcase sqlBeginKeyword[0]:\n\t\t\t\t\tif hasWordAt(contentStr, sqlBeginKeyword, j) {\n\t\t\t\t\t\tst = append(st, sqlBeginKeyword[0])\n\t\t\t\t\t\tj += len(sqlBeginKeyword) - 1\n\t\t\t\t\t}\n\n\t\t\t\tcase sqlEndKeyword[0]:\n\t\t\t\t\tif !hasWordAt(contentStr, sqlEndKeyword, j) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif ok, after := hasWordAfter(contentStr, sqlIfKeyword, j+len(sqlEndKeyword)); ok {\n\t\t\t\t\t\tif len(st) == 0 || st[len(st)-1] != sqlIfKeyword[0] {\n\t\t\t\t\t\t\treturn nil, errors.New(\"error reading contents: unmatched `END IF` keyword\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\tst = st[:len(st)-1]\n\t\t\t\t\t\tj = after + len(sqlIfKeyword) - 1\n\t\t\t\t\t} else if ok, after := hasWordAfter(contentStr, sqlLoopKeyword, j+len(sqlEndKeyword)); ok {\n\t\t\t\t\t\t//nolint:revive\n\t\t\t\t\t\tif len(st) == 0 || st[len(st)-1] != sqlLoopKeyword[0] {\n\t\t\t\t\t\t\treturn nil, errors.New(\"error reading contents: unmatched `END LOOP` keyword\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\tst = st[:len(st)-1]\n\t\t\t\t\t\tj = after + len(sqlLoopKeyword) - 1\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif len(st) == 0 || st[len(st)-1] != sqlBeginKeyword[0] {\n\t\t\t\t\t\t\treturn nil, errors.New(\"error reading contents: unmatched `END` keyword\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\tst = st[:len(st)-1]\n\t\t\t\t\t\tj += len(sqlEndKeyword) - 1\n\t\t\t\t\t}\n","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/persistence/query_util.go#L116-L152","documentation":"LoadAndSplitQueryFromReaders parses schema SQL/CQL containing BEGIN/IF/LOOP blocks and splits statements. This error means the parser hit an `END IF` while its block stack was empty or its top was not an `IF`, i.e. the schema file has an END IF with no matching IF. It is a parse-time validation of the schema script.","triggerScenarios":"Calling LoadAndSplitQuery/LoadAndSplitQueryFromReaders (or parseSQLStmts/Run) on a schema file whose text contains `END IF` without a preceding `IF ... THEN` at the same nesting level, e.g. comments or strings containing the literal keywords confusing nesting, or a deleted/misplaced IF block.","commonSituations":"Hand-edited schema CQL where an IF block was removed but its END IF remained; keywords appearing inside string literals/comments in an unexpected order; a file concatenated in the wrong order; a mistakenly uppercase/lowercase variant that skips IF detection while still matching END IF.","solutions":["Open the schema file and pair every `IF ... THEN` with its `END IF`; fix or remove the unmatched END IF","Check whether the opening IF is commented out or inside a string; restore it","Diff the file against the upstream schema to spot a dropped/renumbered block","If content is generated, fix the generator so IF/END IF are emitted together"],"exampleFix":"// before (schema.cql)\nDROP INDEX IF EXISTS idx;\nEND IF;\n// after\nIF x THEN\n  DROP INDEX idx;\nEND IF;\n","handlingStrategy":"validation","validationCode":"func checkIfEndIfBalance(content string) error {\n    depth := 0\n    words := strings.Fields(strings.ToUpper(content))\n    for _, w := range words {\n        if w == \"IF\" { depth++ }\n        if w == \"END IF\" || (w == \"END\") { depth-- } // approximate; use the library's tokenizer for exactness\n        if depth < 0 { return errors.New(\"END IF without matching IF\") }\n    }\n    if depth != 0 { return errors.New(\"unclosed IF\") }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep IF/END IF pairs adjacent and indented so mismatches are visually obvious","Never leave block keywords inside comments/strings in a way that mimics real syntax","Validate schema files with LoadAndSplitQueryFromReaders in CI before shipping schema updates","Diff hand-edits against upstream schema files"],"tags":["sql-parsing","schema","parser"],"backgroundTag":"unmatched-sql-block-keyword","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}