FOUNDATION · CONTAINER WITHDRAWAL

How to Make a Screeps Creep Withdraw Energy from a Container

Find a Container that currently holds Energy, check the Creep's free capacity, call withdraw(), handle range and return codes, and keep the delivery task outside this focused guide.

Verification statusChinese source article: Reviewed in full · Official docs: Checked — Creep.withdraw(), Room.find(), StructureContainer · API and constants: Checked

VERIFICATION

Evidence and test status

Chinese source article
Reviewed in full
Official docs
Checked — Creep.withdraw(), Room.find(), StructureContainer
API and constants
Checked
JavaScript syntax
Passed
Offline logic review
Passed — missing Creep, full Store, no Container, range, error logging
Screeps Console test
Pending
Live multi-tick room test
Pending
Last verified
July 25, 2026

Quick answer

Use creep.withdraw(container, RESOURCE_ENERGY) to move Energy from a Container into a Creep. First confirm that the Creep has free Store capacity and that the Container currently holds Energy. If the method returns ERR_NOT_IN_RANGE, move toward the Container and retry on a later tick. Save every return value so withdrawal and movement failures remain distinguishable.

withdraw() and transfer() use opposite directions

CallResource direction
creep.withdraw(container, RESOURCE_ENERGY)Container → Creep
creep.transfer(spawn, RESOURCE_ENERGY)Creep → Spawn

Use the delivery tutorial when the Creep already carries Energy. This article only handles acquisition from one Container.

Prerequisites and read-only checks

The example expects a Creep named Hauler1 with active CARRY and MOVE parts. Run this read-only Console check before changing the main loop:

const creep = Game.creeps.Hauler1;

console.log(JSON.stringify({
  creepFound: Boolean(creep),
  spawning: creep ? creep.spawning : null,
  activeCarry: creep ? creep.getActiveBodyparts(CARRY) : null,
  activeMove: creep ? creep.getActiveBodyparts(MOVE) : null,
  freeEnergyCapacity: creep
    ? creep.store.getFreeCapacity(RESOURCE_ENERGY)
    : null
}));

A body may contain a CARRY part while having no active CARRY ability after damage. The complete script checks active parts and Store capacity separately. Review WORK, CARRY, and MOVE when either value is unexpected.

Find a Container that currently has Energy

function findContainerWithEnergy(creep) {
  return creep.pos.findClosestByPath(
    FIND_STRUCTURES,
    {
      filter: structure =>
        structure.structureType === STRUCTURE_CONTAINER
        && structure.store.getUsedCapacity(
          RESOURCE_ENERGY
        ) > 0
    }
  );
}

The result can be null. A room may contain no Container, every Container may be empty, or no valid path may be available. Do not pass a missing result into withdraw().

Complete focused example

State impact: this script may move Hauler1 and withdraw Energy from one Container. It does not deliver the Energy afterward and does not write Memory.

function findContainerWithEnergy(creep) {
  return creep.pos.findClosestByPath(
    FIND_STRUCTURES,
    {
      filter: structure =>
        structure.structureType === STRUCTURE_CONTAINER
        && structure.store.getUsedCapacity(
          RESOURCE_ENERGY
        ) > 0
    }
  );
}

module.exports.loop = function () {
  const creep = Game.creeps.Hauler1;

  if (!creep) {
    console.log('Hauler1 was not found.');
    return;
  }

  if (creep.spawning) {
    return;
  }

  if (creep.getActiveBodyparts(CARRY) <= 0) {
    console.log('Hauler1 has no active CARRY part.');
    return;
  }

  const freeCapacity =
    creep.store.getFreeCapacity(RESOURCE_ENERGY);

  if (freeCapacity === null || freeCapacity <= 0) {
    return;
  }

  const container = findContainerWithEnergy(creep);

  if (!container) {
    console.log(
      'No reachable Container with Energy was found.'
    );
    return;
  }

  const withdrawResult = creep.withdraw(
    container,
    RESOURCE_ENERGY
  );

  if (withdrawResult === ERR_NOT_IN_RANGE) {
    const moveResult = creep.moveTo(container, {
      range: 1,
      reusePath: 5
    });

    if (
      moveResult !== OK
      && moveResult !== ERR_TIRED
    ) {
      console.log(
        'Hauler1 moveTo() returned '
        + moveResult
      );
    }

    return;
  }

  if (withdrawResult !== OK) {
    console.log(
      'Hauler1 withdraw() returned '
      + withdrawResult
    );
  }
};

The target is selected again on later ticks. Its Store can change because another Creep withdraws first, so the filter does not remove the need to inspect the actual API result.

Return-code troubleshooting

ResultMeaningAction
OKThe command was accepted for this tick.Inspect both Stores on a later tick.
ERR_NOT_IN_RANGEThe target is not adjacent.Move toward it and retry later.
ERR_NOT_ENOUGH_RESOURCESThe target lacks the requested resource amount.Refresh target and Store data.
ERR_FULLThe Creep has no free capacity.Switch to a delivery task.
ERR_INVALID_TARGETThe object cannot be used as a withdrawal target.Check existence and target type.
ERR_BUSYThe Creep is still spawning.Wait until spawning finishes.
ERR_INVALID_ARGSThe resource type or amount is invalid.Inspect the arguments.

Use the English Screeps error-code reference when movement or a less common result needs separate diagnosis.

Verify Store changes on a later tick

Official debugging guidance notes that an accepted command is not the same as a verified final state. Record a before snapshot, submit the action, then inspect the next tick:

console.log(JSON.stringify({
  tick: Game.time,
  creepEnergy:
    creep.store.getUsedCapacity(RESOURCE_ENERGY),
  containerEnergy:
    container.store.getUsedCapacity(RESOURCE_ENERGY)
}));

Do not assume that the filtered amount remains unchanged. Another Creep may compete for the same Container during the tick.

Why this guide does not use working state

A working flag is useful when one Creep alternates between acquisition and delivery, but it is not an argument to withdraw(). This guide isolates target selection, capacity checks, action submission, range handling, and return-code logging. Add cross-tick task switching only after the single withdrawal works. See Screeps Memory basics.

Debugging checklist

  • Confirm the Creep name and capitalization.
  • Wait until the Creep finishes spawning.
  • Check for at least one active CARRY part.
  • Check free Store capacity before calling withdraw().
  • Filter for STRUCTURE_CONTAINER and positive Energy.
  • Handle a missing or unreachable target.
  • Save withdrawResult and moveResult separately.
  • Retry the action on later ticks instead of expecting one call to finish the trip.
  • Verify Creep and Container Store changes after the command.

Scope and next steps

This example does not choose among Containers by logistics priority, reserve targets for multiple haulers, withdraw from Storage, Tombstones, or Ruins, construct Containers, or decide where the Energy should be delivered. Continue with picking up dropped Energy to learn the separate API for ground resources.

Frequently asked questions

What direction does withdraw() move Energy?

It moves Energy from the target Container into the calling Creep.

Why does withdraw() return ERR_NOT_IN_RANGE?

The Creep must be adjacent. Move toward the target and retry on a later tick.

Why does withdraw() return ERR_FULL?

The Creep has no free Store capacity for the selected resource.

Does OK prove that Energy arrived?

No. It proves that the API accepted the command. Confirm the Store values after tick processing.

Official documentation

SOURCE AND SCOPE

Review the source, evidence, or next system

This English guide is rewritten for a focused search intent while preserving the technical scope and verification boundaries of its Chinese source. Live-room evidence is claimed only when the verification record says it exists.