# Capture errors and releases

> Send actionable errors, keep grouping useful, and resolve production stack frames.

Canonical page: https://anectico.com/docs/instrument/errors/


Anectico groups similar error events into Issues. Good error context makes those Issues easier to
prioritize and connects them to the customers and releases they affected.

Automatic grouping uses the error type, normalized message, and application stack frames. The
message contributes once, after normalization. Stack headers and other non-frame lines, including
exception-chain continuations such as `Caused by:`, are ignored. Runtime frames such as Node
task-queue and timer internals are also ignored, so raw messages and concurrency-dependent async
scheduling details do not split one application failure into multiple Issues. Browser frames are
recognized in V8's `at function (location)` form, Firefox and Safari's `function@location` form, and
the older two-line `function` then `location` form, so browser call sites do not fall back to
stackless grouping.

## Capture unexpected failures

Use your SDK's error method inside an existing error boundary. Continue to preserve the application's
normal failure behavior.

<div data-language-tabs="capture-error" data-language-tabs-label="Choose an SDK"></div>

**JavaScript / TypeScript**

```typescript
try {
  await chargeCard();
} catch (error) {
  anectico.captureError(error as Error, {
    tags: { component: 'payments' },
  });
  throw error;
}
```

**Python**

```python
try:
    charge_card()
except Exception as error:
    client.capture_error(error, tags={'component': 'payments'})
    raise
```

**Go**

```go
if err := chargeCard(ctx); err != nil {
	client.CaptureError(ctx, err, anectico.WithTag("component", "payments"))
	return err
}
```

**Swift (iOS)**

```swift
do {
    try chargeCard()
} catch {
    Anectico.captureError(error, options: CaptureOptions(tags: ["component": "payments"]))
    throw error
}
```

**Kotlin (Android)**

```kotlin
try {
    chargeCard()
} catch (error: Exception) {
    Anectico.captureError(error, CaptureOptions(tags = mapOf("component" to "payments")))
    throw error
}
```

**React Native**

```typescript
try {
  await chargeCard();
} catch (error) {
  await Anectico.captureError(error, { tags: { component: 'payments' } });
  throw error;
}
```

**Flutter**

```dart
try {
  await chargeCard();
} catch (error, stackTrace) {
  await Anectico.captureError(
    error,
    stackTrace,
    options: const CaptureOptions(tags: {'component': 'payments'}),
  );
  rethrow;
}
```

<div data-language-tabs-end="capture-error"></div>

Do not capture expected validation failures as errors. Use a diagnostic event when the outcome is
useful investigation context but does not require engineering action.

## Add useful context

Prefer low-cardinality tags such as component, operation, or payment provider. Customer identity
should come from the active identity context, not from a duplicate error tag.

SDKs encode capture tags into Anectico's indexed tag namespace automatically. In the Issues list,
severity and handled/unhandled state appear beside the Issue when supplied; the Issue detail shows
the selected occurrence's severity, handling, mechanism, route, release/distribution, SDK/platform,
device model, OS, and app version/build context when available. Use
`error.handled`, `error.mechanism`, and `app.route` when an integration knows those values.

The native Android and iOS SDKs own their error/crash semantics. Caught errors are handled and
nonfatal; uncaught exceptions and native crash paths are unhandled and fatal. Application tags
cannot override those automatic values. The iOS runtime context is privacy-safe and does not
collect a physical-device identifier.

Never attach passwords, authorization headers, access tokens, or unfiltered request bodies.

## Set release and distribution

Every production build should send a stable release identifier. Use `dist` when the same release has
multiple artifacts.

<div data-language-tabs="error-release" data-language-tabs-label="Choose an SDK"></div>

**JavaScript / TypeScript**

```typescript
const anectico = await new AnecticoClient({
  apiKey: process.env.ANECTICO_API_KEY,
  serviceName: 'web',
  release: process.env.GIT_SHA,
  dist: 'browser',
}).start();
```

**Python**

```python
client = anectico.AnecticoClient(
    api_key=os.environ['ANECTICO_API_KEY'],
    service_name='payments',
    service_version=os.environ['RELEASE'],
)
```

**Go**

```go
client, err := anectico.New(
	anectico.WithAPIKey(os.Getenv("ANECTICO_API_KEY")),
	anectico.WithServiceName("payments"),
	anectico.WithServiceVersion(os.Getenv("RELEASE")),
	anectico.WithErrorRelease(os.Getenv("RELEASE")),
)
```

**Swift (iOS)**

```swift
Anectico.configure(AnecticoOptions(
    apiKey: apiKey,
    release: release,
    dist: buildNumber
))
```

**Kotlin (Android)**

```kotlin
Anectico.init(
    applicationContext,
    AnecticoOptions(apiKey = apiKey, release = release, dist = buildNumber),
)
```

**React Native**

```typescript
await Anectico.configure({ apiKey, release, dist: buildNumber });
```

**Flutter**

```dart
await Anectico.configure(AnecticoOptions(
  apiKey: apiKey,
  release: release,
  dist: buildNumber,
));
```

<div data-language-tabs-end="error-release"></div>

Python currently uses the service version as the release identifier. In Go, `WithErrorRelease`
sets the release for error occurrences and takes precedence over `WithServiceVersion`; when it is
omitted, error tracking falls back to `service.version`. Neither SDK currently exposes a separate
`dist` field. Keep the selected error release identical to the release registered by CI.
Mobile and JavaScript integrations can additionally distinguish release-keyed symbol artifacts with
`dist`. JavaScript source maps and Android ProGuard mappings use release/distribution keys. iOS
dSYMs do not: each native frame matches an organization-scoped dSYM slice by exact Mach-O image UUID.

## Upload symbols in CI

The Anectico CLI supports JavaScript source maps, Android ProGuard/R8 mappings, and iOS dSYMs.

```bash
anectico symbols upload-proguard mapping.txt --release "$RELEASE" --dist "$DIST"
anectico symbols upload-dsym MyApp.dSYM
anectico symbols upload-sourcemap --file sourcemap-upload.json
```

For iOS, pass either the `.dSYM` bundle or its exact Mach-O/DWARF file. Preserve the archive that
produced the installed binary because matching uses its exact image UUID, not release or
distribution. Symbol uploads require `errors:write`; add `releases:write` only when the CI job also
registers a release.
Each upload is attributed to the CLI's active project (`--project` or the selected profile project)
and authenticated user/API key. Anectico commits a body-free audit record with the exact artifact keys,
platform, project, actor, size, and SHA-256 in the same transaction as the artifact; source-map,
mapping, and dSYM contents are never copied into audit metadata.

Upload one JavaScript source map per minified filename. `sourcemap-upload.json` has this shape; the
`content` value is the raw `.map` JSON encoded as a JSON string:

```json
{
  "release": "web@2.4.1",
  "dist": "browser",
  "filename": "assets/app.js",
  "content": "{\"version\":3,\"sources\":[\"src/app.ts\"],\"names\":[],\"mappings\":\"\"}"
}
```

Run uploads after building and before deleting artifacts. Keep symbols private. JavaScript map
`content` may be at most 8 MiB after JSON decoding. Because JSON string escaping can make the
request file larger than the decoded map, use the dedicated `upload-sourcemap` command rather than
an unrelated generic JSON-body command. The command injects the active project when `project_id` is
not already present in the request file. Native upload limits are enforced separately. Issue Story
reports missing and mismatched JavaScript maps with the occurrence's exact release, distribution,
and normalized minified filenames while keeping raw bundled frames inspectable. A mismatch means
that an artifact exists but its exact keys or mappings did not resolve the captured position; it
does not mean symbolication succeeded.

## Verify

Trigger one test error from a release build. In **Issues**, confirm the stack points to application
source and that the affected customer and release are present.

- [Triage an Issue](/docs/investigate/triage-issue)
- [Replay or symbols are not working](/docs/help/replay-and-symbols)
