{"record":{"id":"7207bb9597a3911d","repo":"ory/hydra","slug":"failed-to-write-json-output","errorCode":null,"errorMessage":"failed to write json output","messagePattern":"failed to write json output","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"oryx/jsonnetsecure/cmd.go","lineNumber":64,"sourceCode":"\t\t\t// so we still continue in this case.\n\t\t\tSetVirtualMemoryLimit(virtualMemoryLimitBytes)\n\n\t\t\tif null {\n\t\t\t\treturn scan(cmd.OutOrStdout(), cmd.InOrStdin())\n\t\t\t}\n\n\t\t\tinput, err := io.ReadAll(cmd.InOrStdin())\n\t\t\tif err != nil {\n\t\t\t\treturn errors.Wrap(err, \"failed to read from stdin\")\n\t\t\t}\n\n\t\t\tjson, err := eval(input)\n\t\t\tif err != nil {\n\t\t\t\treturn errors.Wrap(err, \"failed to evaluate jsonnet\")\n\t\t\t}\n\n\t\t\tif _, err := io.WriteString(cmd.OutOrStdout(), json); err != nil {\n\t\t\t\treturn errors.Wrap(err, \"failed to write json output\")\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\tcmd.Flags().BoolVarP(&null, \"null\", \"0\", false,\n\t\t`Read multiple snippets and parameters from stdin separated by null bytes.\nOutput will be in the same order as inputs, separated by null bytes.\nEvaluation errors will also be reported to stdout, separated by null bytes.\nNon-recoverable errors are written to stderr and the program will terminate with a non-zero exit code.`)\n\n\treturn cmd\n}\n\nfunc scan(w io.Writer, r io.Reader) error {\n\tscanner := bufio.NewScanner(r)\n\tscanner.Split(splitNull)\n\tfor scanner.Scan() {\n\t\tjson, err := eval(scanner.Bytes())","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/oryx/jsonnetsecure/cmd.go#L46-L82","documentation":"This error wraps a failure to write the evaluated jsonnet result to the process's stdout in the single-snippet (non `-0`) mode of the hidden `jsonnet` CLI command. The evaluation itself succeeded; only the final `io.WriteString(cmd.OutOrStdout(), json)` failed. It usually indicates the parent process that spawned this child has closed or stopped reading its stdout pipe.","triggerScenarios":"Running the jsonnet subprocess worker, evaluating a snippet successfully, then `io.WriteString` on stdout returns an error — typically EPIPE because the parent closed the read end of the pipe, or stdout was redirected to a full/unwritable file or closed descriptor.","commonSituations":"Parent process killed or exited while the worker was still evaluating; parent hit its 1s eval timeout and closed the pipe; stdout redirected to a disk-full filesystem or a file with wrong permissions; running the command interactively with stdout closed (e.g. `jsonnet >&-`).","solutions":["Check that the parent process keeps the child's stdout pipe open until the child exits, and drains it promptly","Verify stdout redirection targets are writable and have free space (df, ls -l on the target)","If the parent imposes a 1s timeout, keep snippets small so evaluation finishes before the parent gives up","Re-run the command manually with a simple snippet like `{}` to confirm the environment, not the snippet, is at fault"],"exampleFix":"// before: parent discards the cmd immediately on timeout\ncmd := exec.Command(path, args...)\n_ = cmd.Run()\n// after: ensure pipes are drained until the child exits\nvar out bytes.Buffer\ncmd.Stdout = &out\nerr := cmd.Run() // keeps reading stdout so the child never gets EPIPE","handlingStrategy":"try-catch","validationCode":"// parent side: verify stdout is a usable pipe/file before spawning\nif f, ok := os.Stdout.(*os.File); ok {\n    if _, err := f.Stat(); err != nil {\n        return fmt.Errorf(\"stdout unusable: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if _, err := io.WriteString(cmd.OutOrStdout(), json); err != nil {\n    if errors.Is(err, syscall.EPIPE) {\n        // parent closed the pipe; exit quietly\n        return nil\n    }\n    return errors.Wrap(err, \"failed to write json output\")\n}","preventionTips":["Always drain the child's stdout in the parent, even after a timeout, before killing it","Check redirection targets for writability and disk space in deployment scripts","Keep evaluations short so parents with 1s timeouts don't abandon the pipe mid-write","Use cmd.Wait() and capture combined output in tests to surface pipe issues early"],"tags":["go","io","broken-pipe","subprocess","stdout"],"backgroundTag":"broken-pipe-stdout","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}