Programming & Scripting Errors May 20, 2026

Bevy 0.17 "Component Is Already Required" Panic - Sprite Migration From SpriteBundle - How to Fix

Fix Bevy 0.17 required-components panic when migrating from SpriteBundle. Remove duplicate #[require] derives, reorder add_plugins, and spawn without conflicting component graphs.

By GamineAI Team

Bevy 0.17 "Component Is Already Required" Panic - Sprite Migration From SpriteBundle - How to Fix

Problem: After upgrading to Bevy 0.17, App::run() panics immediately at startup:

Component `Transform` is already required by component `Sprite`

You replaced SpriteBundle { ... } with Sprite::from_image(...) per the new docs, but the app never reaches your first system.

Who is affected now: Teams porting 0.13/0.14 tutorial code in 2026, plugins that add their own #[require(Transform)] on leaf components, and projects that register plugins in an order that registers the same required edge twice.

Fastest safe fix: Read the panic for both component names (X already required by Y), remove the duplicate #[require(...)] on your custom component (or stop manually requiring what Bevy core already requires), then reorder add_plugins so framework plugins register before game plugins.

Direct answer

Bevy 0.17 required components attach defaults automatically when you spawn Sprite, Camera2d, or Node. The panic means two different components in the type graph both declared the same required edge — usually your #[require(Transform)] on a custom component plus Bevy’s built-in requirements on Sprite. Delete the redundant require, fix plugin registration order, and spawn from a single root without chaining duplicate requires on parent and child.

Why this issue spikes in 2026

  1. Required components replaced bundles as the default teaching path in 0.16/0.17 (Q1–Q2 2026).
  2. Most indie Bevy repos still mix 0.13-era chapter code with new spawn snippets.
  3. Third-party plugins copied #[require(Transform)] patterns from pre-0.17 blog posts.

Pair the fix with the Bevy 0.17 Required Components, Observers, and Asset Hot Reload guide chapter and, if textures do not refresh after you fix the panic, Bevy 0.17 Asset Hot Reload Silent.

Symptoms and phrases to match

  • Panic before window opens; cargo test also fails on App startup.
  • Message names two components — not a missing component error.
  • Occurs right after deleting SpriteBundle / Camera2dBundle.
  • Adding #[require(Transform)] on both Player and a child Weapon sprite.
  • Panic only when a specific third-party plugin is enabled.

Root causes (check in this order)

  1. Duplicate #[require] — your component requires Transform while spawning under Sprite (which already requires Transform).
  2. Plugin double-registration — two plugins register conflicting required-component metadata for the same pair.
  3. Non-deterministic plugin orderadd_plugins order changes which require wins until panic.
  4. Tuple spawn with redundant requires — parent and child both carry the same require path.
  5. Copied 0.13 bundle + 0.17 sprite in the same spawn function.

Fastest safe fix path

Step 1 - Parse the panic (both sides matter)

Example:

Component `Transform` is already required by component `Sprite`
  • Already required: Transform (the dependency being attached twice).
  • Required by: Sprite (Bevy core already owns this edge).

If your custom Player also has #[require(Transform)], remove it from Player when you spawn with Sprite:

// Before (conflicts with Sprite's built-in requires)
#[derive(Component)]
#[require(Transform, Visibility)]
struct Player;

// After (let Sprite supply Transform / Visibility)
#[derive(Component)]
struct Player;

Step 2 - One root spawn pattern

Prefer a single spawn graph:

commands.spawn((
    Sprite::from_image(asset_server.load("player.png")),
    Transform::from_xyz(0.0, 0.0, 0.0),
    Player,
));

Do not also #[require(Transform)] on Player unless Player spawns without Sprite.

Step 3 - Reorder plugins

Register Bevy defaults before game plugins that touch required components:

App::new()
    .add_plugins(DefaultPlugins)
    .add_plugins(MyGamePlugin)  // after DefaultPlugins
    .run();

If the panic disappears when you disable MyGamePlugin, inspect that plugin’s #[require(...)] derives.

Step 4 - Startup spawn test (CI guard)

#[test]
fn app_starts_without_required_component_panic() {
    App::new()
        .add_plugins(MinimalPlugins)
        .add_systems(Startup, setup_player_sprite)
        .update();
}

Run on every PR that touches #[require] or plugin registration.

Alternative branches

Branch A — Custom component must always have Transform

Spawn Player without Sprite when you need a bare transform:

commands.spawn((
    Player,
    Transform::default(),
    Visibility::default(),
));

Branch B — Third-party plugin conflict

Temporarily binary-search plugins. File an issue with the plugin author: required edges must not duplicate Bevy core’s graph.

Branch C — Still on 0.16 tutorials

Pin bevy = "0.17" in Cargo.toml and complete the modernization chapter in one pass — mixing bundle and require APIs in one file always panics.

Verification checklist

  • [ ] cargo run reaches first frame without panic.
  • [ ] bevy_dev_tools / ECS inspector shows Transform once on player entity.
  • [ ] cargo test startup test passes in CI.
  • [ ] No #[require(Transform)] on components spawned with Sprite.
  • [ ] Plugin order documented in lib.rs / main.rs comment.

Prevention

  • Pin minor Bevy version in Cargo.toml; bump only with a migration checklist.
  • Ban new #[require(Transform)] on sprite-tagged components in code review.
  • Add the startup spawn test above to the default template.
  • When importing 0.13 snippets, run rg "SpriteBundle|Camera2dBundle" and replace in one commit.

Troubleshooting table

Symptom Likely cause Fix
Panic names Sprite + Transform Duplicate require on custom component Remove #[require(Transform)] from leaf
Panic only with UI + sprites Node and custom UI require clash Separate plugins; check Node requires
Intermittent panic on clean build Plugin order differs debug vs release Fix add_plugins order explicitly
Panic after adding derive macro Proc-macro injected #[require] Inspect expanded code / disable macro
Compile OK, panic at runtime Required graph validated at startup Use startup test, not only cargo check

Frequently asked questions

Q: Should I add #[require(Transform)] on every game component?

A: Only when that component spawns without Bevy types that already require Transform. Sprites, cameras, and UI nodes already carry the graph.

Q: Can I keep SpriteBundle on 0.17?

A: Bundles are removed/deprecated on the modernization path — migrate to Sprite::from_image + explicit overrides.

Q: Does this affect observers or hot reload?

A: No — but fix the panic first; otherwise you never reach systems that use observers or reload assets.

Q: Panic mentions a third-party component name?

A: That plugin registered a conflicting require — reorder plugins or patch the plugin version.

Related help articles and guides

Bookmark this page when your 0.16 → 0.17 port hits a startup panic — the fix is almost always a duplicate require edge, not a broken sprite image.