ipfs/kubo · error

internal error encoding node

Error message

internal error encoding node

What it means

The actual encoding of the DAG node runs in a detached goroutine writing into an io.Pipe, because codecs are third-party code and a panic there would kill the whole daemon. If the encoder panics, the goroutine recovers it, logs a stack trace, and closes the pipe with the error "internal error encoding node", which surfaces to the client as the command's failure.

Solutions

  1. Check the daemon log for the recovered-panic message with stack trace to identify the codec
  2. Retry with --output-codec=dag-json or another codec to work around the faulty encoder
  3. Report the panic (with the stack trace) to the codec/kubo project
  4. Upgrade kubo / the codec library to a version with the panic fixed
Defensive patterns

Strategy: fallback

Try / catch

// CLI: retry with a different output codec on internal encoding error
out, err := exec.Command("ipfs", "dag", "get", cid).Output()
if err != nil && strings.Contains(errText(err), "internal error encoding node") {
    out, err = exec.Command("ipfs", "dag", "get", "--output-codec=dag-json", cid).Output()
}

Prevention

When it happens

Trigger: `ipfs dag get` where a registered multicodec encoder panics on the node being serialized (buggy codec implementation, node shape the codec cannot handle).

Common situations: Corrupt or unusual DAG node structures fed to dag-pb/dag-cbor encoders; bugs in custom codec plugins; rare upstream ipld codec regressions.

Related errors


AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03). Data as JSON: /api/errors/526d7e5d9afeae2b. Report an issue: GitHub.

Appendix: source

Thrown at core/commands/dag/get.go:79

			return err
		}
	}

	encoder, err := multicodec.LookupEncoder(uint64(codec))
	if err != nil {
		return fmt.Errorf("invalid encoding: %s - %s", codec, err)
	}

	r, w := io.Pipe()
	go func() {
		defer w.Close()
		// Encoding runs the codec named by the node's CID, so it runs
		// third-party code. This goroutine is detached from the request, and a
		// panic on it would end the daemon rather than the command.
		defer func() {
			if rec := recover(); rec != nil {
				log.Errorf("recovered from panic encoding %s as %s: %v\n%s", p, codec, rec, debug.Stack())
				_ = w.CloseWithError(errors.New("internal error encoding node"))
			}
		}()
		if err := encoder(finalNode, w); err != nil {
			_ = w.CloseWithError(err)
		}
	}()

	return res.Emit(r)
}

View on GitHub (pinned to 329838acdf)