---
title: "MGS3002: VCS unavailable"
description: A vcs host-module call could not resolve a version control system, or the VCS command it ran failed, so the value it was asked for does not exist.
tags:
  [MGS3002, vcs, git, host-modules, errors, magusfile]
---

# MGS3002: VCS unavailable

A `vcs` call could not produce the value it was asked for. Either no VCS is
resolved for the workspace, or one is resolved and the command it ran failed.

```text
[MGS3002] read git metadata: exit status 128
```

## Why this raises instead of returning ""

These accessors used to return an empty string, and `vcs.commit()` returned a
record with every field blank. Both are gone.

An empty string is a value a branch name or a commit subject can legitimately
hold, so testing for it could never distinguish "there is no answer" from "the
answer is empty". It also made the check optional: a magusfile that forgot
`if (h == "")` interpolated an empty commit into a version string or an image
tag, and nothing surfaced until somebody read the artifact.

## Resolution

Building outside a checkout is a real case - a release tarball, a container
build context, a vendored copy - so catch it where that is expected:

```buzz
fun commit() > str {
    try {
        return vcs\shortHash();
    } catch (e) {
        return "unknown";
    }
}
```

To ask whether a VCS exists at all without catching, use `vcs\name()`. It
returns `""` when nothing is resolved and never raises - the detection half of
the pair, the same split as `os\env` and `os\lookupEnv`.

Note that `name()` reports the resolved DRIVER. With git installed it answers
`"git"` even outside a repository, because the driver resolved and the
repository is what is missing.

## Catching it by code

The error reaches `catch` as a map, so a magusfile can branch on the code
rather than matching text:

```buzz
try {
    final h = vcs\shortHash();
} catch (e) {
    if (e["code"] == "MGS3002") {
        magus\info("no VCS here; stamping the build as unknown");
    }
}
```

## What still returns a value

`vcs\isDirty()` reports `false` when no VCS is resolved at all - a known state
that genuinely answers "is anything dirty?". It RAISES only when a VCS exists
and its status probe fails, because then the question was never answered. A
drift gate must never be told "clean" by a check that did not run.
