kopia/kopia · error

unable to parse object ID

Error message

unable to parse object ID

What it means

Returned when the string passed as a root ID to pinSnapshotsByRootObjectID cannot be parsed into a Kopia object ID via object.ParseID. Object IDs have a strict format (hex content hash, possibly with an encryption prefix), so any malformed or non-ID string fails here.

Solutions

  1. Pass a valid root object ID (hex content-hash format) when pinning by root.
  2. Use `kopia snapshot list --json` to find snapshots and their rootObjectID values.
  3. If you intended to pin a specific snapshot, use its full snapshot ID instead.

Example fix

// before
kopia snapshot pin /home/user
// after
kopia snapshot list --json | jq -r '.[].rootEntry.obj'  # get valid root OID
kopia snapshot pin <rootObjectID>
Defensive patterns

Strategy: validation

Validate before calling

// validate root object ID format before calling
if _, err := object.ParseID(rootID); err != nil {
    return fmt.Errorf("%q is not a valid object ID: %v", rootID, err)
}

Try / catch

rootOID, err := object.ParseID(rootID)
if err != nil {
    return errors.Wrapf(err, "unable to parse object ID %q", rootID)
}

Prevention

When it happens

Trigger: `kopia snapshot pin` was given an ID that is not a snapshot manifest ID, so the code attempts to treat it as a root object ID and object.ParseID(rootID) fails — e.g. a manifest ID like 'k1234...', a path, or a name was passed.

Common situations: User passes a snapshot manifest ID (prefixed 'k') hoping to pin by root; passing a human-readable source path like '/home/user' instead of an ID; shell truncation of a copied ID.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07). Data as JSON: /api/errors/bd9722ac3d490776. Report an issue: GitHub.

Appendix: source

Thrown at cli/command_snapshot_pin.go:52

		m, err := snapshot.LoadSnapshot(ctx, rep, manifest.ID(id))
		if err == nil {
			if err = c.pinSnapshot(ctx, rep, m); err != nil {
				return errors.Wrapf(err, "error pinning %v", id)
			}
		} else if !errors.Is(err, snapshot.ErrSnapshotNotFound) {
			return errors.Wrapf(err, "error loading snapshot %v", id)
		} else if err := c.pinSnapshotsByRootObjectID(ctx, rep, id); err != nil {
			return errors.Wrapf(err, "error pinning snapshots by root ID %v", id)
		}
	}

	return nil
}

func (c *commandSnapshotPin) pinSnapshotsByRootObjectID(ctx context.Context, rep repo.RepositoryWriter, rootID string) error {
	rootOID, err := object.ParseID(rootID)
	if err != nil {
		return errors.Wrap(err, "unable to parse object ID")
	}

	manifests, err := snapshot.FindSnapshotsByRootObjectID(ctx, rep, rootOID)
	if err != nil {
		return errors.Wrapf(err, "unable to find snapshots by root %v", rootID)
	}

	if len(manifests) == 0 {
		return errors.Errorf("no snapshots matched %v", rootID)
	}

	for _, m := range manifests {
		if err := c.pinSnapshot(ctx, rep, m); err != nil {
			return errors.Wrap(err, "error pinning")
		}
	}

	return nil

View on GitHub (pinned to 82495e54b5)