{"record":{"id":"9792b6852e4078c1","repo":"nektos/act","slug":"cannot-parse-non-string-type-v-as-json","errorCode":null,"errorMessage":"Cannot parse non-string type %v as JSON","messagePattern":"Cannot parse non-string type (.+?) as JSON","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/exprparser/functions.go","lineNumber":170,"sourceCode":"\t}\n}\n\nfunc (impl *interperterImpl) toJSON(value reflect.Value) (string, error) {\n\tif value.Kind() == reflect.Invalid {\n\t\treturn \"null\", nil\n\t}\n\n\tjson, err := json.MarshalIndent(value.Interface(), \"\", \"  \")\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"Cannot convert value to JSON. Cause: %v\", err)\n\t}\n\n\treturn string(json), nil\n}\n\nfunc (impl *interperterImpl) fromJSON(value reflect.Value) (interface{}, error) {\n\tif value.Kind() != reflect.String {\n\t\treturn nil, fmt.Errorf(\"Cannot parse non-string type %v as JSON\", value.Kind())\n\t}\n\n\tvar data interface{}\n\n\terr := json.Unmarshal([]byte(value.String()), &data)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"Invalid JSON: %v\", err)\n\t}\n\n\treturn data, nil\n}\n\nfunc (impl *interperterImpl) hashFiles(paths ...reflect.Value) (string, error) {\n\tvar ps []gitignore.Pattern\n\n\tconst cwdPrefix = \".\" + string(filepath.Separator)\n\tconst excludeCwdPrefix = \"!\" + cwdPrefix\n\tfor _, path := range paths {","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/nektos/act/blob/4f411281417e88660bea1c1a1749aa71ae0bd60f/pkg/exprparser/functions.go#L152-L188","documentation":"Thrown by fromJSON() when its argument is not reflect.String. GitHub's fromJSON only accepts a JSON string; passing a number, boolean, array, or object value directly is rejected before parsing.","triggerScenarios":"fromJSON(inputs.myjson) where the input was declared type: number (so it arrives as a number); fromJSON(github.event.pull_request) which is already an object; double conversion fromJSON(fromJSON(x)).","commonSituations":"Workflow inputs typed incorrectly in workflow_dispatch inputs; assuming fromJSON also serializes (use toJSON for that); data already parsed upstream.","solutions":["Only pass strings to fromJSON; for already-object values just use them directly.","Fix the input's declared type (string instead of number/boolean) in workflow_dispatch inputs.","Use toJSON() when you need the opposite direction.","Wrap non-strings: pass the raw JSON text, not a parsed structure."],"exampleFix":"# before\ninputs:\n  cfg:\n    type: number\n...\n${{ fromJSON(inputs.cfg) }}\n# after\ninputs:\n  cfg:\n    type: string\n...\n${{ fromJSON(inputs.cfg) }}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isStringy(v interface{}) bool {\n  return reflect.TypeOf(v) == nil || reflect.TypeOf(v).Kind() == reflect.String\n}","tryCatchPattern":"if v, err := fromJSON(x); err != nil {\n  if strings.Contains(err.Error(), 'non-string') {\n    // already structured data: use as-is instead of parsing\n    return x\n  }\n  return err\n}","preventionTips":["Declare JSON inputs as type: string in workflow_dispatch","Use toJSON for the reverse direction","Do not double-parse already-decoded values"],"tags":["expressions","from-json","type-mismatch","workflow-yaml"],"backgroundTag":null,"analyzedSha":"4f411281417e88660bea1c1a1749aa71ae0bd60f","analyzedAt":"2026-08-15T09:19:46.307Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}