{"record":{"id":"74c9ad2fed5ffedc","repo":"nektos/act","slug":"the-following-format-string-is-invalid-s","errorCode":null,"errorMessage":"The following format string is invalid: '%s'","messagePattern":"The following format string is invalid: '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/exprparser/functions.go","lineNumber":97,"sourceCode":"\n\t\t\tcase '}':\n\t\t\t\tstate = bracketClose\n\n\t\t\tdefault:\n\t\t\t\toutput += string(character)\n\t\t\t}\n\n\t\tcase bracketOpen: // found {\n\t\t\tswitch character {\n\t\t\tcase '{':\n\t\t\t\toutput += \"{\"\n\t\t\t\treplacementIndex = \"\"\n\t\t\t\tstate = passThrough\n\n\t\t\tcase '}':\n\t\t\t\tindex, err := strconv.ParseInt(replacementIndex, 10, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", fmt.Errorf(\"The following format string is invalid: '%s'\", input)\n\t\t\t\t}\n\n\t\t\t\treplacementIndex = \"\"\n\n\t\t\t\tif len(replaceValue) <= int(index) {\n\t\t\t\t\treturn \"\", fmt.Errorf(\"The following format string references more arguments than were supplied: '%s'\", input)\n\t\t\t\t}\n\n\t\t\t\toutput += impl.coerceToString(replaceValue[index]).String()\n\n\t\t\t\tstate = passThrough\n\n\t\t\tdefault:\n\t\t\t\treplacementIndex += string(character)\n\t\t\t}\n\n\t\tcase bracketClose: // found }\n\t\t\tswitch character {","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/nektos/act/blob/4f411281417e88660bea1c1a1749aa71ae0bd60f/pkg/exprparser/functions.go#L79-L115","documentation":"Thrown by the expression format() function when a {...} placeholder's index part cannot be parsed as an integer (strconv.ParseInt fails). GitHub's format() only supports {0}, {1}, ... placeholders, so '{foo}' or '{}' with empty accumulated index text yields this error.","triggerScenarios":"A workflow expression like format('Hello {name}', inputs.name) — literal braces must be escaped as '{{' and '}}'; format('{a}') with no valid integer; empty index '{}'.","commonSituations":"Trying to use Python/JS-style named placeholders in format(); writing JSON templates inside format() without doubling braces; migrating from other template engines.","solutions":["Use positional placeholders: format('Hello {0}', name).","Escape literal braces: '{{' and '}}' for literal { and } in the output.","For JSON output prefer toJSON() instead of format().","Check the workflow locally with actionlint, which flags malformed format strings."],"exampleFix":"# before\nrun: echo ${{ format('Hi {name}', github.actor) }}\n# after\nrun: echo ${{ format('Hi {0}', github.actor) }}","handlingStrategy":"validation","validationCode":"var ph = regexp.MustCompile(`\\{([^}]*)\\}`)\nfunc validPlaceholders(s string) bool {\n  s = strings.ReplaceAll(s, '{{', '').ReplaceAll(s, '}}', '')\n  for _, m := range ph.FindAllStringSubmatch(s, -1) {\n    if _, err := strconv.Atoi(m[1]); err != nil { return false }\n  }\n  return true\n}","typeGuard":null,"tryCatchPattern":"if _, err := parser.Format(tpl, args...); err != nil {\n  if strings.Contains(err.Error(), 'invalid') { tpl = sanitizePlaceholders(tpl) } else { return err }\n}","preventionTips":["Use only integer placeholders {0},{1}...","Escape literal braces as {{ }}","Lint workflows with actionlint before committing"],"tags":["expressions","format-function","workflow-yaml","placeholder"],"backgroundTag":null,"analyzedSha":"4f411281417e88660bea1c1a1749aa71ae0bd60f","analyzedAt":"2026-08-15T09:19:46.307Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}