ipfs/kubo · error
pin: %s
Error message
pin: %s
What it means
PinAPI.Add first resolves the given path to a node; any resolution failure (bad path, unsupported namespace, missing block) is wrapped with a 'pin: ' prefix. The error is a wrapper — the underlying cause (from ResolveNode) is embedded after the prefix.
Source
Thrown at core/coreapi/pin.go:30
pin "github.com/ipfs/boxo/pinning/pinner"
"github.com/ipfs/go-cid"
coreiface "github.com/ipfs/kubo/core/coreiface"
caopts "github.com/ipfs/kubo/core/coreiface/options"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"github.com/ipfs/kubo/tracing"
)
type PinAPI CoreAPI
func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOption) error {
ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Add", trace.WithAttributes(attribute.String("path", p.String())))
defer span.End()
dagNode, err := api.core().ResolveNode(ctx, p)
if err != nil {
return fmt.Errorf("pin: %s", err)
}
settings, err := caopts.PinAddOptions(opts...)
if err != nil {
return err
}
span.SetAttributes(attribute.Bool("recursive", settings.Recursive))
defer api.blockstore.PinLock(ctx).Unlock(ctx)
err = api.pinning.Pin(ctx, dagNode, settings.Recursive, settings.Name)
if err != nil {
return fmt.Errorf("pin: %s", err)
}
return api.pinning.Flush(ctx)
}View on GitHub (pinned to 329838acdf)
Solutions
- Read the wrapped cause after 'pin: ' to identify the real failure
- Verify the CID exists locally: 'ipfs block stat' or 'ipfs cat'
- Resolve IPNS/namespace issues before pinning (pin the /ipfs/ path)
- Ensure the daemon has connectivity to fetch the content before pinning
Example fix
// before
err := api.Pin().Add(ctx, path.New("/ipns/example.com")) // pin: unsupported path namespace
// after
nd, err := api.ResolveNode(ctx, path.New("/ipns/example.com"))
if err == nil {
err = api.Pin().Add(ctx, path.FromCid(nd.Cid()))
} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure path is /ipfs/-namespaced and the CID is present locally
_, err := api.Block().Stat(ctx, p)
if err != nil {
// fetch/resolve before pinning
} Type guard
func isIPFSPath(p path.Path) bool { return p.Namespace() == path.IPFSNamespace } Try / catch
err := api.Pin().Add(ctx, p, opts...)
if err != nil {
var cause error
if strings.HasPrefix(err.Error(), "pin: ") {
// unwrap and inspect the resolution failure after "pin: "
}
return fmt.Errorf("pin add failed: %w", err)
} Prevention
- Resolve paths to /ipfs/ CIDs before pinning
- Verify content availability (block stat / cat) before pin add
- Use errors.Is/As on the wrapped cause when possible
When it happens
Trigger: Calling Pin().Add with a path that cannot be resolved: nonexistent CID, /ipns/ path, malformed path, or a path whose blocks are not present locally and cannot be fetched.
Common situations: Pinning a CID that exists on the network but the node is offline; pinning an IPNS name without the pin API supporting that namespace; typo'd CID.
Related errors
- error resolving path: %s
- http api returned no error and no results
- out.Err (server-provided error message)
- n.Err (server-provided bad-node error message)
- cannot return size for anything other than a DAG with a root
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/84e001e3600ee732.
Report an issue: GitHub.