abpframework/abp · error · FormatException
There is no closing } char for an opened { char.
Error message
There is no closing } char for an opened { char. What it means
After the tokenizer loop finishes scanning every character, it checks whether inDynamicValue is still true. If so, an opening '{' was never closed by a '}', and it throws FormatException for the unterminated dynamic segment. Used by FormattedStringValueExtracter.Extract/IsMatch.
Source
Thrown at framework/src/Volo.Abp.Core/Volo/Abp/Text/Formatting/FormatStringTokenizer.cs:67
var dynamicValue = currentText.ToString();
if (includeBracketsForDynamicValues)
{
dynamicValue = "{" + dynamicValue + "}";
}
tokens.Add(new FormatStringToken(dynamicValue, FormatStringTokenType.DynamicValue));
currentText.Clear();
break;
default:
currentText.Append(c);
break;
}
}
if (inDynamicValue)
{
throw new FormatException("There is no closing } char for an opened { char.");
}
if (currentText.Length > 0)
{
tokens.Add(new FormatStringToken(currentText.ToString(), FormatStringTokenType.ConstantText));
}
return tokens;
}
}
View on GitHub (pinned to 7ed43b1931)
Solutions
- Close the dynamic segment: "a{b}" instead of "a{b".
- Validate brace balance (equal counts and correct open/close ordering) before invoking Extract.
- Catch FormatException around Extract for untrusted format input and treat it as a non-match.
Example fix
// before: opening brace never closed
var r = FormattedStringValueExtracter.Extract(input, "user-{id");
// throws FormatException: no closing } for the opened {
// after: close the dynamic segment
var r = FormattedStringValueExtracter.Extract(input, "user-{id}"); Defensive patterns
Strategy: try-catch
Validate before calling
static bool IsBraceBalanced(string format)
{
if (format.IsNullOrEmpty()) return true;
var depth = 0;
foreach (var c in format)
{
if (c == '{') depth++;
else if (c == '}') { if (depth == 0) return false; depth--; }
}
return depth == 0; // false when an opening brace was never closed
}
if (!IsBraceBalanced(format)) { /* reject template */ } Try / catch
try
{
result = FormattedStringValueExtracter.Extract(str, format);
}
catch (FormatException)
{
result = new ExtractionResult(false);
} Prevention
- Validate brace balance for every template at load time.
- Avoid truncating templates via Substring/concatenation that may drop a closing brace.
- Store complete templates in one place and unit-test them.
- Treat format strings as code: review and test them, do not assemble ad hoc at runtime.
When it happens
Trigger: Calling FormattedStringValueExtracter.Extract(str, format) with a format whose last dynamic segment has no closing brace: "a{b", "name-{id", or "{unclosed" (test case at FormattedStringTokenizer_Test.cs:13 tokenizes "a sample { wrong format").
Common situations: Truncated template strings; formats assembled by string concatenation that dropped the trailing '}; user-edited config that accidentally deleted a brace; copy-paste that cut off the end of a template.
Related errors
- Incorrect syntax at char {i}! format string can not contain
- Incorrect syntax at char {i}! These is no opening brackets f
- Incorrect syntax at char {i}! Brackets does not containt any
- Should specify an option name after '--' prefix!
- Should specify an option name after '-' prefix!
AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13).
Data as JSON: /api/errors/d4bd4dd12f5a922b.
Report an issue: GitHub.