GETTING STARTED · HARVESTING

How to Harvest Energy With Your First Creep

CURATED PATH

These links are maintained for a concrete prerequisite, failure mode, debugging step, or next lesson instead of generic topic similarity.

Beginner / Energy

Recommended next steps

Transfer Energy to a SpawnNext lessonCreep body partsPrerequisite conceptWorking-state switchingState-machine upgrade
Verification statusChinese source article: Reviewed in full · Official documentation: Checked August 29, 2026 — Creep.harvest(), Creep Store capacity, FIND_SOURCES_ACTIVE, and current-tick action return semantics · Official engine source: Checked current screeps/engine master — Source harvest submission has no Store-capacity ERR_FULL preflight; the processor drops overflow beyond Creep Store capacity

VERIFICATION

Evidence and test status

Chinese source article
Reviewed in full
Official documentation
Checked August 29, 2026 — Creep.harvest(), Creep Store capacity, FIND_SOURCES_ACTIVE, and current-tick action return semantics
Official engine source
Checked current screeps/engine master — Source harvest submission has no Store-capacity ERR_FULL preflight; the processor drops overflow beyond Creep Store capacity
Static code review
Passed — the minimal loop preserves harvest and movement results separately, and the larger-body capacity guard is scoped to an unboosted Source-harvesting policy
Screeps Console test
Pending — no live Source-harvest trace is claimed
Live multi-tick verification
Pending
Live Source-overflow test
Pending — no live near-full, full-Store, or dropped-overflow comparison is claimed
Evidence level
Official documentation, official engine source, repository review and offline code checks; no Console or live-shard evidence claimed
Last editorial review
August 29, 2026
Publication status
Published

Quick answer

To harvest Energy, pick an active Source, call creep.harvest(source), and move toward it when the result is ERR_NOT_IN_RANGE. When the Creep has no free Energy capacity left, stop the harvesting phase and move on to delivery.

The important beginner distinction is simple: Store capacity is Creep state; the value returned by harvest() is an action result. Do not wait for ERR_FULL to tell you the Store is full. Source harvesting does not return ERR_FULL.

Start with this minimal harvesting loop

Pass one of your Creeps into this function. It does not assume a particular Creep name, room name, or Source ID:

function harvestEnergy(creep) {
  const freeEnergy =
    creep.store.getFreeCapacity(RESOURCE_ENERGY);

  if (freeEnergy === null || freeEnergy === 0) {
    return { status: 'ready-for-delivery' };
  }

  const source =
    creep.pos.findClosestByPath(FIND_SOURCES_ACTIVE);

  if (!source) {
    return { status: 'no-active-source' };
  }

  const harvestResult = creep.harvest(source);
  let moveResult = null;

  if (harvestResult === ERR_NOT_IN_RANGE) {
    moveResult = creep.moveTo(source, {
      range: 1,
      reusePath: 5
    });
  }

  return {
    status: harvestResult === OK
      ? 'harvest-accepted'
      : 'harvest-not-accepted',
    sourceId: source.id,
    harvestResult,
    moveResult
  };
}

A normal first trip is easy to read: while the Store has room, find an active Source; if the Source is too far away, move; once adjacent, harvest() can return OK; when the Store is full, leave this acquisition function and run the delivery step.

What happens each tick

  1. Read Store state. getFreeCapacity(RESOURCE_ENERGY) decides whether this role still needs to acquire Energy.
  2. Choose a usable Source. FIND_SOURCES_ACTIVE avoids choosing a currently empty Source in this beginner loop.
  3. Submit the harvest action. If the Creep is adjacent and the other API conditions are satisfied, harvest() returns OK.
  4. Handle range separately. If harvesting returns ERR_NOT_IN_RANGE, submit movement and keep the movement result separate from the harvest result.
  5. Run the loop again next tick. Screeps processes intents after your player code, so OK is not the same thing as a later observed Store increase.

This separation makes debugging much easier. You can tell whether the problem is current state, the harvest call, or movement instead of collapsing all three into one boolean.

When should the Creep stop harvesting?

For a first Creep that harvests and then carries Energy to another object, the simplest phase boundary is:

Free Energy capacity available → harvest. No free Energy capacity → deliver.

That rule is enough to understand the basic loop. Once ready-for-delivery is returned, hand the Creep to your delivery logic instead of continuing to call harvest().

This is application state, not a special harvest return code. In particular, do not write role logic that waits for creep.harvest(source) === ERR_FULL. The current Source-harvest API path has no Store-capacity ERR_FULL preflight.

Source-specific Creep.harvest() return codes

This lesson is scoped to Source Energy. Minerals and Deposits have additional conditions, so keep their branches out of a first Source-harvesting loop.

ResultWhat it means hereNext step
OKThe harvest intent was accepted for this tick.Check the later visible Source and Store state if you need proof of the processed result.
ERR_NOT_IN_RANGEThe Creep is not adjacent to the Source.Move to range 1, then retry on a later tick.
ERR_NOT_ENOUGH_RESOURCESThe Source currently has no Energy.Wait for regeneration or choose another active Source.
ERR_NO_BODYPARTNo active WORK part is available.Inspect the Creep body and damage.
ERR_BUSYThe Creep is still spawning.Wait until spawning is complete.
ERR_INVALID_TARGETThe object passed to this call is not a valid harvest target.Resolve the Source again.
ERR_NOT_OWNERThe actor or room ownership/reservation boundary does not allow this Source harvest.Check Creep ownership and the room Controller state.

ERR_FULL is deliberately absent. Some other Creep APIs use ERR_FULL, but it is not a universal Store-capacity result and is not returned by Source harvest().

Why use FIND_SOURCES_ACTIVE?

FIND_SOURCES_ACTIVE gives this beginner loop Sources that currently contain Energy. That reduces one avoidable failure branch while you are learning the action flow.

This is a target-selection policy, not a requirement of harvest(). A dedicated miner can stay assigned to one Source and wait for regeneration; a general-purpose first worker usually benefits from selecting an active Source.

Harden the capacity boundary after the basic loop works

The full-Store rule above is intentionally minimal. A larger unboosted Creep can have several active WORK parts, so one Source harvest batch can be larger than the remaining Store capacity.

The current public engine processor adds the harvested amount and drops overflow when total carried resources exceed Store capacity. For a mobile beginner worker, deliberately overflowing the Store is usually unnecessary. Linqingan therefore uses this conservative project policy for an unboosted Source-harvesting carrier: if the Creep already carries Energy and the remaining capacity is smaller than the next full Source batch, switch to delivery a little early.

function getHarvestCapacityState(creep) {
  const activeWork = creep.getActiveBodyparts(WORK);
  const usedEnergy =
    creep.store.getUsedCapacity(RESOURCE_ENERGY) ?? 0;
  const freeEnergy =
    creep.store.getFreeCapacity(RESOURCE_ENERGY) ?? 0;
  const energyCapacity =
    creep.store.getCapacity(RESOURCE_ENERGY) ?? 0;
  const nextBatch = activeWork * HARVEST_POWER;

  if (energyCapacity <= 0) {
    return 'no-energy-capacity';
  }

  if (nextBatch > energyCapacity) {
    return 'body-store-mismatch';
  }

  if (
    freeEnergy === 0
    || (usedEnergy > 0 && freeEnergy < nextBatch)
  ) {
    return 'ready-for-delivery';
  }

  return 'can-harvest';
}

body-store-mismatch means one unboosted Source batch is larger than the Creep's entire Energy capacity. Change the body or use a deliberate drop-mining design instead of pretending all of that batch can fit.

This formula is not an official Screeps recommendation. It is a local policy for the unboosted beginner body in this lesson. Boosted WORK parts need a different batch calculation.

Debug state, action, and movement separately

LayerQuestionEvidence to inspect
StateShould this Creep still be acquiring Energy?store.getUsedCapacity() and store.getFreeCapacity().
ActionWas the Source harvest accepted?The exact value returned by harvest().
MovementIf range failed, was movement accepted?The separate moveTo() result and the later Creep position.

If you overwrite the harvest result with the movement result, you lose the evidence that tells you which layer failed.

How to verify the loop in your room

Start with read-only observations. Pick your actual Creep rather than copying a placeholder name, then inspect its Store, active WORK parts, position, and the active Sources visible in its room.

When testing the loop, preserve the harvestResult. If it is OK, inspect a later tick when you need to confirm the processed Source/Store change. If it is ERR_NOT_IN_RANGE, preserve the separate movement result and verify that the Creep's later position changed as expected.

Evidence boundary: the API and public engine paths above were reviewed, but this article does not claim a captured live full-Store or near-full overflow trace. Those runtime cases remain Pending.

Next lesson

Once the Creep is ready to deliver, continue with Creep-to-Spawn Energy delivery. If the harvest action keeps returning ERR_NOT_IN_RANGE, use the range debugging guide to separate pathing and movement failures from the harvest call.

Official sources

SOURCE AND SCOPE

Review the source, evidence, or next system

This English guide keeps the technical scope and verification boundaries of its Chinese source. The verification record shows which checks were completed and which runtime observations are still pending.