# Warnings as errors RFC

**URL:** <https://community.tuist.dev/t/warnings-as-errors-rfc/907>\
**Category:** RFCs\
**Created:** [February 23, 2026, 7:43pm UTC](https://community.tuist.dev/t/warnings-as-errors-rfc/907 "2026-02-23T19:43:10Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![marekfort](https://community.tuist.dev/user_avatar/community.tuist.dev/marekfort/32/8_2.png) [@marekfort](https://community.tuist.dev/u/marekfort)\
**Post date:** [February 23, 2026, 7:43pm UTC](https://community.tuist.dev/t/warnings-as-errors-rfc/907/1 "2026-02-23T19:43:10Z")

</div>

# RFC: Selective Warnings as Errors in `tuist generate`

## Summary

Allow project maintainers to promote specific generation warnings to errors via `GenerationOptions` in `Tuist.swift`, so that `tuist generate` fails immediately when those warnings are detected.

## Motivation

Today, `tuist generate` emits warnings at the end of generation that are easy to miss. For example, the “outdated dependencies” warning tells the user to run `tuist install`, but since generation succeeds, developers often overlook it and end up debugging subtle breakages caused by stale dependencies.

A real-world example from a Tuist adopter:

> I missed the outdated dependencies warning, then had a subtle breakage that took me a moderate amount of time to track down. It would be better if we could just fail immediately.

There was a prior discussion about adding a `--strict` flag that would treat _all_ warnings as errors, but that approach is too blunt — teams may not be able to address every warning immediately (e.g., static side effects warnings during a migration period). What’s needed is a way to selectively promote specific warnings to errors, similar to Swift 6’s warnings-as-errors model.

Importantly, this should be a **manifest-level configuration** (in `GenerationOptions`), not a CLI flag, so that platform teams can enforce policy for all developers rather than relying on each individual to pass the right flags.

## Prior Art

- **Swift compiler** : `-warnings-as-errors` flag and, since Swift 6, selective `#warning` / `-Werror=<category>` support.
- **ESLint** : Rules can be individually set to `"off"`, `"warn"`, or `"error"`.
- **Gradle** : Specific deprecation warnings can be promoted to errors via configuration.
- **Bazel** : `--check_direct_dependencies=error` promotes a specific warning to an error.

All of these share the same pattern: a default severity that can be overridden per-category.

## Proposed Solution

### New `GenerationOptions` Parameter

Add a new `warningsAsErrors` parameter to `Tuist.GenerationOptions` in `Tuist.swift`:

```swift
// ProjectDescription

extension Tuist.GenerationOptions {
    public enum WarningsAsErrors: Codable, Equatable, Sendable {
        /// No warnings are promoted to errors (default, current behavior).
        case none
        /// All generation warnings are treated as errors.
        case all
        /// Only the specified warning categories are treated as errors.
        case only(Set<GenerationWarning>)
    }
}

```

### Warning Categories

Define an enum of known warning categories:

```swift
// ProjectDescription

public enum GenerationWarning: String, Codable, Equatable, Hashable, Sendable {
    /// Dependencies are outdated compared to the resolved package graph.
    case outdatedDependencies
    /// A static product is linked from multiple targets, risking side effects.
    case staticSideEffects
    /// A scheme references targets that cannot be found.
    case schemeTargetNotFound
    /// Project configurations are mismatched across the graph.
    case mismatchedConfigurations
    /// Duplicate product names exist among dependencies.
    case duplicateProductNames
}

```

### Usage

```swift
// Tuist.swift

let tuist = Tuist(
    project: .tuist(
        generationOptions: .options(
            warningsAsErrors: .only([.outdatedDependencies])
        )
    )
)

```

Or to enforce all warnings as errors:

```swift
let tuist = Tuist(
    project: .tuist(
        generationOptions: .options(
            warningsAsErrors: .all
        )
    )
)

```

### Behavior

When `warningsAsErrors` is configured and a matching warning is triggered:

1. The warning is displayed as an error (red, not yellow).
2. Generation **fails** with a non-zero exit code.
3. The error message includes the same content as the warning, plus guidance on how to resolve it.

When a warning is _not_ in the promoted set, the current behavior is preserved — the warning is printed at the end and generation succeeds.

### Implementation Sketch

The core change is in the linting pipeline. Currently, `LintingIssue` has a fixed severity set at creation time. The proposed approach:

1. After collecting all linting issues in `Generator`, check the `warningsAsErrors` configuration.
2. For each `.warning`-severity issue that matches a promoted category, elevate it to `.error`.
3. The existing error-handling path (which already throws `LintingError` for `.error` issues) takes care of the rest.

This requires adding a `category: GenerationWarning?` field to `LintingIssue` so that warnings can be identified by type rather than by string matching on the reason.

Key files to modify:

- `Sources/ProjectDescription/ConfigGenerationOptions.swift` — add `warningsAsErrors` option
- `Sources/TuistCore/Models/LintingIssue.swift` — add optional `category` field
- `Sources/TuistKit/Generator/Generator.swift` — elevate matching warnings before printing
- `Sources/TuistGenerator/Linter/GraphLinter.swift` — tag warnings with categories
- `Sources/TuistGenerator/Linter/StaticProductsGraphLinter.swift` — tag warnings
- `Sources/TuistLoader/Loaders/SwiftPackageManagerGraphLoader.swift` — tag outdated dependencies warning

### Relationship to `staticSideEffectsWarningTargets`

The existing `staticSideEffectsWarningTargets` option controls _which targets_ trigger static side effects warnings. The new `warningsAsErrors` option is orthogonal — it controls _what happens_ when a warning is triggered. Both can coexist:

```swift
.options(
    staticSideEffectsWarningTargets: .excluding(["LegacyModule"]),
    warningsAsErrors: .only([.staticSideEffects, .outdatedDependencies])
)

```

This means: “Don’t warn about LegacyModule’s static side effects, but if any other target triggers the warning, fail the build.”

## Alternatives Considered

### 1. `--strict` CLI flag

Treats all warnings as errors. Too blunt — teams in migration periods can’t suppress specific warnings. Also requires each developer to remember to pass the flag, making it unsuitable for enforcing team policy.

### 2. Per-warning suppression instead of promotion

An `.ignoreWarnings([...])` option that suppresses specific warnings. This is the inverse of the proposal and could complement it, but doesn’t solve the core problem of making critical warnings enforceable. Could be added later.

### 3. CLI flag instead of manifest option

A `--warnings-as-errors` flag on `tuist generate`. This puts the burden on individual developers and doesn’t allow platform teams to enforce policy. The manifest-level approach is preferred because it’s checked into source control and applies to everyone.

## Open Questions

1. **Should we also support `--warnings-as-errors` as a CLI flag?** It could be useful for CI environments that want stricter checks than local development. The manifest option could serve as the baseline, with the CLI flag providing an override. I’m leaning to no for now and we can add it if this becomes a need.

---

<div class="post-metadata">

**Author:** ![pepicrft](https://community.tuist.dev/user_avatar/community.tuist.dev/pepicrft/32/5_2.png) [@pepicrft](https://community.tuist.dev/u/pepicrft)\
**Post date:** [February 24, 2026, 10:43am UTC](https://community.tuist.dev/t/warnings-as-errors-rfc/907/2 "2026-02-24T10:43:47Z")

</div>

Very onboard with the plan.

> [@marekfort](#):
>
> 1. **Should we also support `--warnings-as-errors` as a CLI flag?** It could be useful for CI environments that want stricter checks than local development. The manifest option could serve as the baseline, with the CLI flag providing an override. I’m leaning to no for now and we can add it if this becomes a need.

I’d say let’s do if teams ask for it.

---

<div class="post-metadata">

**Author:** ![marekfort](https://community.tuist.dev/user_avatar/community.tuist.dev/marekfort/32/8_2.png) [@marekfort](https://community.tuist.dev/u/marekfort)\
**Post date:** [February 24, 2026, 12:29pm UTC](https://community.tuist.dev/t/warnings-as-errors-rfc/907/3 "2026-02-24T12:29:25Z")

</div>

PR to implement this: [feat(cli): add warningsAsErrors generation option by fortmarek · Pull Request #9574 · tuist/tuist · GitHub](https://github.com/tuist/tuist/pull/9574)
